Javascript 删除以前添加的不工作的类

Javascript 删除以前添加的不工作的类,javascript,Javascript,我正在用js为一篇文章添加一个类,这一切都正常,没问题。但是,如果我想删除这个类,这种方法是行不通的。我不能使用jQuery document.AddEventListenerDomainContentLoaded,函数{ var blogCard=document.querySelectorAll'[data role=blogCard]'; 对于let i=0;i

我正在用js为一篇文章添加一个类,这一切都正常,没问题。但是,如果我想删除这个类,这种方法是行不通的。我不能使用jQuery

document.AddEventListenerDomainContentLoaded,函数{ var blogCard=document.querySelectorAll'[data role=blogCard]'; 对于let i=0;i 要解决这个问题,您可以只在第二个处理程序中阻止事件传播,或者只使用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中的目标位置——如果有一个单亲,向这些卡的父级应用一个事件处理程序,当然:

// 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中的所有卡。

因为单击事件会传播到父级,所以这里实际上会触发两个单击处理程序。button.closeCard click处理程序删除该类,但div.blogCard one将其添加回:这就是为什么添加类有效,而删除类无效

要解决这个问题,您可以只在第二个处理程序中阻止事件传播,或者只使用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中的目标位置——如果有一个单亲,向这些卡的父级应用一个事件处理程序,当然:

// 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中的所有卡。

在代码中,每次打开卡时,都会向文档中的第一张closeCard添加一个事件

如果您有超过1张卡,则此操作无效

尝试添加两个单独的事件:

document.AddEventListenerDomainContentLoaded,函数{ //获取博客卡 var blogCard=document.querySelectorAll'[data role=blogCard]'; //接近卡片 var closeCard=document.querySelectorAll'[data role=closeCard]'; 对于let i=0;i这段代码可以优化如果您知道blogCard和closeCard之间的DOM关系,您不需要单独查询这两个角色,但我将把它留给OP

在您的代码中,您每次打开一张卡片时,都会向文档中的第一张closeCard添加一个事件

如果您有超过1张卡,则此操作无效

尝试添加两个单独的事件:

document.AddEventListenerDomainContentLoaded,函数{ //获取博客卡 var blogCard=document.querySelectorAll'[data role=blogCard]'; //接近卡片 var closeCard=document.querySelectorAll'[data role=closeCard]'; 对于let i=0;i这段代码可以优化如果您知道blogCard和closeCard之间的DOM关系,您不需要单独查询这两个角色,但是我将把它留给OP

在循环中分配这样的事件侦听器是可能的,正如其他答案所示,但这不是最简单或最有效的选择。使用带有Element.matches条件的全局单击侦听器更好,因为:

在代码中更简单、更容易理解。 它的效率更高,并且在页面变得可交互后不需要立即依赖同步循环。 它允许您在DOMContentReady激发后添加其他卡,而无需任何特殊处理;侦听器将听到在单击时与选择器匹配的所有元素。 window.addEventListener单击,函数E{ console.logClick!,e.target; 如果e.target.matches[data role='blogCard']{ e、 target.classList.add'opened-card'; } 如果e.target.matches[data role='closeCard']{ e、 target.parentElement.classList.remove'opened-card'; } }; .打开的卡{ 背景:红色; } 关
正如其他答案所示,在循环中分配这样的事件侦听器是可能的,但这不是最简单或最有效的选择。使用带有Element.matches条件的全局单击侦听器更好,因为:

在代码中更简单、更容易理解。 它的效率更高,并且在页面变得可交互后不需要立即依赖同步循环。 它允许您在DOMContentReady激发后添加其他卡,而无需任何特殊处理;侦听器将听到在单击时与选择器匹配的所有元素。 window.addEventListener单击,函数E{ console.logClick!,e.target; 如果e.target.matches[data role='blogCard']{ e、 target.classList.add'opened-card'; } 如果e.target.matches[data role='closeCard']{ e、 target.parentElement.classList.remove'opened-card'; } }; .打开的卡{ 背景:红色; } 关
没问题,发生在我们所有人身上。当看到奇怪的东西时,通常最好的办法是一行一行地调试它,以了解全局。没问题,我们所有人都会遇到。当看到奇怪的东西时,通常最好的办法是逐行调试它,以了解全局。在特定元素上设置EventListener的能力是有原因的。虽然这种方法当然是可能的,但有几个警告。该代码不仅会在每次单击页面时调用,而且会以静默方式创建一个全局假设,即每个“data role=closeCard”都会触发其父级上“已打开的卡”的移除。此外,如果blogCard的结构发生变化,则不再匹配就足够了,相反,应该检查“closestdata role=blogCard”。是的,将事件处理程序绑定到容器是一个好主意,但如果不看OP的情况,很难建议它是否足够接近blog Card。我提到的变化不是活的;例如,如果有人决定在blogCards中添加标题div,该怎么办?或者出于装饰的原因在“.blogCard”结构中做一些其他修改?这也将导致事件处理程序发生更改,并且该选择器将不再匹配event.target;应该改为使用最接近的。第一次回复时意外删除,所以这里有一个重新创建的有效点。您可以简单地将侦听器范围限定为父元素,而不是窗口,例如document.getElementByIdcardContainer.addEventListener,它解决了您的前两个问题。至于最后一个问题,让一个监听器同时处理所有元素实际上更容易修改,但是如果卡片的结构和关闭它们的条件在页面处于活动状态时发生变化,这是卡本身的一个实现问题。我认为与您提到的原因相同——我们不知道卡的全部内容,很难证明一种解决方案优于另一种解决方案。您的if-close按钮else也容易受到相同的需求变化问题的影响。我支持这样一种观点,即所有元素的非循环事件监听器同时反映了更好的实践。看到了吗?我有没有说过反对将事件委派作为一种技巧——特别是考虑到在回答中使用了它?当然不是;这都是关于实现的:1不要在DOM中将事件处理程序设置得太高,因为最终会有很多东西挂在那里——函数和它们的作用域;2而不是.matches,检查.nextest,因为DOM中的任何更改都会破坏您的委派。我们之所以能够在特定元素上设置eventListeners是有原因的。虽然这种方法当然是可能的,但有几个警告。这段代码不仅会在每次点击页面时被调用,而且会无声地创建一个全局假设,即每个“da”
ta role=closeCard“应触发其父级上已打开卡的移除”。此外,如果blogCard的结构发生变化,则不再匹配就足够了,相反,应该检查“closestdata role=blogCard”。是的,将事件处理程序绑定到容器是一个好主意,但如果不看OP的情况,很难建议它是否足够接近blog Card。我提到的变化不是活的;例如,如果有人决定在blogCards中添加标题div,该怎么办?或者出于装饰的原因在“.blogCard”结构中做一些其他修改?这也将导致事件处理程序发生更改,并且该选择器将不再匹配event.target;应该改为使用最接近的。第一次回复时意外删除,所以这里有一个重新创建的有效点。您可以简单地将侦听器范围限定为父元素,而不是窗口,例如document.getElementByIdcardContainer.addEventListener,它解决了您的前两个问题。至于最后一个问题,让一个监听器同时处理所有元素实际上更容易修改,但是如果卡片的结构和关闭它们的条件在页面处于活动状态时发生变化,这是卡本身的一个实现问题。我认为与您提到的原因相同——我们不知道卡的全部内容,很难证明一种解决方案优于另一种解决方案。您的if-close按钮else也容易受到相同的需求变化问题的影响。我支持这样一种观点,即所有元素的非循环事件监听器同时反映了更好的实践。看到了吗?我有没有说过反对将事件委派作为一种技巧——特别是考虑到在回答中使用了它?当然不是;这都是关于实现的:1不要在DOM中将事件处理程序设置得太高,因为最终会有很多东西挂在那里——函数和它们的作用域;2而不是.matches,检查.closest,因为DOM中的任何更改都会破坏您的委派。