【问题标题】:addEventListener on a querySelectorAll() with classList带有 classList 的 querySelectorAll() 上的 addEventListener
【发布时间】:2022-01-14 19:02:27
【问题描述】:

我正在尝试添加事件侦听器,但没有结果。我知道 JavaScript 有一个提升功能,但我相信我尝试了所有方法,除了正确的解决方案。

const cbox = document.querySelectorAll(".box");
function doit() {
  for (let i = 0; i < cbox.length; i++){
    cbox[i].classList.add("red");
  }
}
cbox.addEventListener("click", doit, false);

有人能看出我犯的错误吗?

【问题讨论】:

  • 为什么要在doit() 中使用循环来添加red 类?
  • 因为 querySelectorAll 返回一个对象,所以必须迭代对吗?
  • 是的,它返回一个类似数组的对象。下一个问题是:为什么不使用循环来分配事件处理程序? ;)
  • 您的意思是在处理程序中运行 for 循环,反之亦然?我都试过了。
  • .querySelectorAll() 返回一个没有 .addEventListener() 方法的 NodeList。您必须在列表中的每个项目上添加事件,就像在类中执行此操作一样。

标签: javascript addeventlistener


【解决方案1】:

代码与您提供的链接之间存在一些差异。里面没有函数doit()

您已将addEvenListener 附加到cbox.addEventListener("click",..... 中的NodeList,您必须遍历列表并将事件附加到当前元素:

尝试以下方法:

const cbox = document.querySelectorAll(".box");

 for (let i = 0; i < cbox.length; i++) {
     cbox[i].addEventListener("click", function() {
       cbox[i].classList.toggle("red");
     });
 }
*,
html,
body {
    padding: 0;
    margin: 0;
}

.box {
    width: 10rem;
    height: 10rem;
    background-color: yellowgreen;
    float: left;
    position: relative;
    margin: 0.5rem;
    transition: .5s all;
}

h3 {
    display: block;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}

.box:not(:first-child) {
    margin-left: 1rem;
}

.red {
    background-color: orangered;
}
<div id="box1" class="box box1">
    <h3>Box 1</h3>
</div>
<div id="box2" class="box box2">
    <h3>Box 2</h3>
</div>
<div id="box3" class="box box3">
    <h3>Box 3</h3>
</div>
<div id="box4" class="box box4">
    <h3>Box 4</h3>
</div>

您还可以使用 Array.prototype.forEach()arrow function 语法,这样您就可以用更少的代码实现相同的目标:

let cbox = document.querySelectorAll(".box");
cbox.forEach(box => {
  box.addEventListener('click', () => box.classList.toggle("red"));
});
*,
html,
body {
    padding: 0;
    margin: 0;
}

.box {
    width: 10rem;
    height: 10rem;
    background-color: yellowgreen;
    float: left;
    position: relative;
    margin: 0.5rem;
    transition: .5s all;
}

h3 {
    display: block;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}

.box:not(:first-child) {
    margin-left: 1rem;
}

.red {
    background-color: orangered;
}
<div id="box1" class="box box1">
    <h3>Box 1</h3>
</div>
<div id="box2" class="box box2">
    <h3>Box 2</h3>
</div>
<div id="box3" class="box box3">
    <h3>Box 3</h3>
</div>
<div id="box4" class="box box4">
    <h3>Box 4</h3>
</div>

【讨论】:

  • 虽然此代码可以回答问题,但提供有关 如何 和/或 为什么 解决问题的附加上下文将改善答案的长期价值。
  • .querySelectorAll() 不返回HTMLCollection,而是返回NodeList
  • 因此,如果它是某种列表,则意味着我们也可以在元素 cbox 上使用 foreach 循环。
  • @EvangelosK.,是的,你是对的。您必须使用循环将事件侦听器附加到每个元素.....谢谢。
  • 谢谢。但就性能问题而言,如果数组中有 20 个项目,该事件会触发 20 次吗?每个元素一个。?
【解决方案2】:

ES6 使这更简单:

document.querySelectorAll(".box").forEach(box => 
  box.addEventListener("click", () => box.classList.toggle("red"))
)

示例实现:

document.querySelectorAll(".box").forEach(box => 
  box.addEventListener("click", () => box.classList.toggle("red"))
)
.box {
    width: 5rem;
    height: 5rem;
    background-color: yellowgreen;
    display: inline-block;
}

.box.red {
    background-color: firebrick;
}
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>

【讨论】:

  • 这是一个更简洁的 ES6 表示法解决方案
【解决方案3】:

您可以在类上使用forEach 或使用事件委托

const cboxes = document.querySelectorAll(".box");
function doit() {
    ... do something ...
}
cboxes.forEach(
  function(cbox) {
   cbox.addEventListener("click", doit,false);
  }
);

请注意,我更改了您的变量名。

EventDelgation

HTML:

<div id="parent">
  <div id="box1" class="box box1">
    <h3>Box 1</h3>
  </div>
  <div id="box2" class="box box2">
      <h3>Box 2</h3>
  </div>
  <div id="box3" class="box box3">
      <h3>Box 3</h3>
  </div>
  <div id="box4" class="box box4">
      <h3>Box 4</h3>
  </div>
</div>

JS部分:

const parent = document.querySelector("#parent");

parent.addEventListener('click', (e) => {
  e.target.classList.add('red');
  console.log(e.target);
});

事件委托要好得多,它使用的资源更少,因为您只使用 1 个事件侦听器并且没有 for 循环。

【讨论】:

  • cboxes.forEach() 不适用于 IE:developer.mozilla.org/en-US/docs/Web/API/NodeList/…
  • Array.prototype.forEach !== NodeList.prototype.forEach
  • 简单的 polyfill 修复以使 forEach 在 NodeList.prototype.forEach = Array.prototype.forEach;
  • 或者你可以像这样使用数组扩展运算符:[...document.querySelectorAll(".box")]
  • parent.addEventListener('click', (e) =&gt; { const tgt = e.target; if (tgt.classList.contains('box')) tgt.classList.add('red'); console.log(tgt.id); });
猜你喜欢
  • 1970-01-01
  • 2021-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-09
  • 1970-01-01
相关资源
最近更新 更多