javascript - Is it okay to store an Object on a DOM element in a vanilla JS plugin?
问题描述
I'm converting jQuery plugins to Vanilla Javascript. I've adopted a Bootstrap-style plugin structure in my example. Once I've instantiated the Accordion object I save it to the dom element so I can later use various methods on the object. Is this an anti-pattern? I would really appreciate any suggestions on how to handle this if it's not correct.
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>
解决方案
我不会担心的。唯一的潜在问题是名称冲突(其他一些代码也尝试分配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 )
推荐阅读
- java - 嵌套列表java 8流之间的交集
- travis-ci - Travis 构建失败并显示“apt-get install failed”
- c# - 无法禁用 LazyLoading
- c - 尽管设置了 -L/usr/lib,但为 MIPS 交叉编译 PortAudio 失败并显示“找不到 -lasound”
- cpu-architecture - 哪个组件管理或向处理器中的控制单元提供指令?
- virtual-machine - 使用 vmware 工作站软件打开 VM 时遇到问题
- jenkins - 运行 SonarQube 扫描仪 - Java/TypeScript
- java - CSVPrinter 数据显示未按列分隔
- java - 多数据库设置中未使用的属性
- java - 如何获取 onTextChanged 以获取edittext promptsView