我正在用js向文章中添加一个类,它的全部正常工作,没问题。但是,如果我想删除该类,则此方法将行不通。我不能使用jQuery。
document.addEventListener("DOMContentLoaded", function() {
var blogCard = document.querySelectorAll('[data-role="blogCard"]');
for (let i = 0; i < blogCard.length; i++) {
blogCard[i].addEventListener('click', function() {
this.classList.add('opened-card');
var closeCard = document.querySelectorAll('[data-role="closeCard"]');
closeCard[0].addEventListener('click', function() {
var pThis = this.parentNode;
pThis.classList.remove('opened-card');
});
});
};
});
<div class="card" data-role="blogCard">
<button data-role="closeCard">Close</button>
</div>
我试图将“删除”更改为“添加”,并且效果很好,它添加了类。但是当我回去删除它时将无法工作。
答案 0 :(得分:4)
由于click
事件传播到父对象,因此实际上在此处触发了两个单击处理程序。 button.closeCard
单击处理程序将删除该类,但div.blogCard
会将其添加回该类。 :)这就是为什么添加一个类可以但不能删除的原因。
要解决此问题,您可以阻止事件在第二个处理程序中传播,或者仅使用在div.blogCard
上设置的组合事件处理程序,并根据event.target
选择行为(本质上实现委托) 。像这样:
blogCard[i].addEventListener('click', function(event) {
if (event.target.getAttribute('data-role') === 'closeCard') {
this.classList.remove('opened-card');
}
else {
this.classList.add('opened-card');
}
});
实际上,您可能会考虑使用相同的技术-在目标DOM inside 事件处理程序中检查目标的位置-通过将单个事件处理程序应用于这些卡的父级(如果有单个父级,则为课程):
// a single event handler set on some 'cardContainer' element
var blogCard = event.target.closest('[data-role="blogCard"]');
if (blogCard) {
var action = event.target.closest('[data-role="closeCard"]') ? 'remove' : 'add';
blogCard.classList[action]('opened-card');
}
正如@IronFlare正确提到的那样,这不仅比单独循环处理每张卡具有更高的性能和可读性,而且还可以在设置事件处理程序之后处理所有添加到DOM中的卡。
答案 1 :(得分:2)
像这样在循环中分配事件侦听器是可能,但这不是最为简单或有效的选择。将全局点击侦听器与Element.matches()
条件一起使用会更好,因为:
DOMContentReady
开火后添加其他卡牌,而无需任何特殊处理;单击时,所有与选择器匹配的元素都将被侦听器“听到”。
window.addEventListener("click", function(e) {
console.log("Click!", e.target);
if (e.target.matches("[data-role='blogCard']")) {
e.target.classList.add('opened-card');
}
if (e.target.matches("[data-role='closeCard']")) {
e.target.parentElement.classList.remove('opened-card');
}
});
.opened-card {
background: red;
}
<div class="card" data-role="blogCard">
<button data-role="closeCard">Close</button>
</div>
答案 2 :(得分:1)
在您的代码中,每次“打开”卡片时,都会将事件添加到文档的第一个“ closeCard”中。
如果您有1张以上的卡,则此操作将无效。
尝试添加2个单独的事件:
document.addEventListener("DOMContentLoaded", function() {
// get blogCards
var blogCard = document.querySelectorAll('[data-role="blogCard"]');
// get closeCards
var closeCard = document.querySelectorAll('[data-role="closeCard"]');
for (let i = 0; i < blogCard.length; i++) {
// apply open event
blogCard[i].addEventListener('click', function() {
this.classList.add('opened-card');
});
// apply respective close event
// this assumes you have one close button for every blogCard
// if it's not the case then maybe you should scope the querySelectors
closeCard[i].addEventListener('click', function() {
var pThis = this.parentNode;
pThis.classList.remove('opened-card');
});
};
});
此代码可以优化(如果您知道blogCard和closeCard之间的DOM关系,则无需单独查询两个“角色”),但我将其留给OP