将对象存储在普通JS插件中的DOM元素上可以吗?

时间:2018-06-21 09:24:30

标签: javascript dom plugins

我正在将jQuery插件转换为Vanilla Javascript。在我的示例中,我采用了Bootstrap风格的插件结构。实例化Accordion对象后,将其保存到dom元素中,以便以后可以对该对象使用各种方法。这是反模式吗?如果不正确,我将非常感谢您提供有关如何处理此问题的建议。

const Accordion = function(element, options){
    this.$element = element;
    this.target = this.$element.getAttribute('href') || this.$element.dataset.target;
    this.$target = document.getElementById(this.target);
    this.$header = document.querySelector(`.accordion-header[data-target='${this.target}']`) || document.querySelector(`.accordion-header[href='${this.target}']`);
    this.options = {...Accordion.defaults, ...options};
}

Accordion.defaults = {
    closeOthers: false
}

Accordion.prototype.open = function(){
    this.$header.classList.add('active');
    this.$target.classList.add('active');
};
Accordion.prototype.close = function(){
    this.$header.classList.remove('active');
    this.$target.classList.remove('active');
};

Accordion.prototype.toggle = function(){
    if(this.$target.classList.contains('active')){
        this.close();   
    } else {
        this.open();
    }
};

function Plugin(options){
    let accordion = this.Accordion;
    if(!accordion){    
        accordion = new Accordion(this, options);
        // Is it okay to store an object on the DOM element?
        this.Accordion = accordion;
    }
}

const $accordions = [...document.querySelectorAll('[data-toggle="accordion"]')];
const options = {
    closeOthers: true
};

/* Call the plugin */

$accordions.forEach($acc => {
    Plugin.call($acc, options);
});

$accordions.forEach($acc => {
    $acc.addEventListener('click', e => {
        e.target.Accordion.toggle();
        e.preventDefault();       
    });
});

const $toggle1 = document.getElementById('toggle1');
const $toggle2 = document.getElementById('toggle2');
const $acc1 = document.getElementById('acc1');    
const $acc2 = document.getElementById('acc2');    

$toggle1.addEventListener('click', e =>{
    $acc1.Accordion.toggle();
});

$toggle2.addEventListener('click', e =>{
    $acc2.Accordion.toggle();
});
body {
    max-width: 500px;
    margin: 0 auto;
    padding: 10px;
}
.accordion {
    border: 1px solid #ccc;
    border-bottom: 0;
    margin-bottom: 10px;
}

.accordion-header {
    display: block;
    padding: 10px;
    text-decoration: none;
    color: #000;
    border-bottom: 1px solid #ccc;

}
.accordion-header.active {
    background: #eee;
}

.accordion-body {
    padding: 10px;
    display: none;
    border-bottom: 1px solid #ccc;
}

.accordion-body.active {
    display: block;
}
<div class="accordion">
    <a id="acc1" href="#1" class="accordion-header" data-toggle="accordion">Header1</a>
    <div id="#1" class="accordion-body">
        Lorem, ipsum dolor sit amet consectetur adipisicing elit. Consequatur aliquid et ipsam cupiditate. Omnis iste quas nostrum aliquid facilis ut natus excepturi deleniti nobis in similique, ex, voluptatibus commodi dolores.
    </div>
</div>

<div class="accordion">
    <a id="acc2" href="#2" class="accordion-header" data-toggle="accordion">Header2</a>
    <div id="#2" class="accordion-body">
        Lorem, ipsum dolor sit amet consectetur adipisicing elit. Consequatur aliquid et ipsam cupiditate. Omnis iste quas nostrum aliquid facilis ut natus excepturi deleniti nobis in similique, ex, voluptatibus commodi dolores.
    </div>
</div>

<button id="toggle1">
    Toggle 1
</button>
<button id="toggle2">
    Toggle 2
</button>

1 个答案:

答案 0 :(得分:1)

我不会为此担心。唯一的潜在问题是名称冲突(某些其他代码也尝试分配给element.Accordion并覆盖它)。您也可以使用Map

var accordions = new Map()
function Accordion ( element ) {
    accordions.set( element, this )
}
Accordion.get = element => accordions.get( element )
...
var accordion = Accordion.get( element )