【问题标题】:Removing event listener using loop removes only last element's listener使用循环删除事件侦听器仅删除最后一个元素的侦听器
【发布时间】:2020-06-04 22:41:18
【问题描述】:

我在 HTML 集合中有 3 个元素,并使用 forEach 循环将 onclick 侦听器附加到它们

[].forEach.call(signBoxes, (e, i) => {
  e.addEventListener("click", callSetSign = () => setSign(signs[i]));
});

function setSign({ name, src }) {
  const sign = name;
  const Img = src;
  player1Choice.src = Img;
  [].forEach.call(signBoxes, (e, i) => {
    e.removeEventListener("click", callSetSign);
  });
  socket.emit("self-choose-sign", sign);
}

添加侦听器可以正常工作,但是当我尝试以相同方式删除它们时,只会删除最后一个元素的侦听器。如果我像这样更改函数,我会得到相同的结果。

function setSign({ name, src }) {
  const sign = name;
  const Img = src;
  player1Choice.src = Img;
  signBoxes[0].removeEventListener('click', callSetSign)
  signBoxes[1].removeEventListener('click', callSetSign)
  signBoxes[2].removeEventListener('click', callSetSign) // only this one works
  socket.emit("self-choose-sign", sign);
}

谁能解释一下?

【问题讨论】:

  • callSetSign = () => setSign(signs[i]) callSetSign 的值。它只会指向分配给它的最后一个箭头函数。这也只会在最后一个迭代的元素上。这可以解释您报告的行为
  • 感谢快速回答,但如果我在循环之前声明 callSetSign,是否可以在不使用绑定的情况下传递参数,以便稍后删除监听器?
  • function callSetSign () { return setSign(this); }e.addEventListener("click", callSetSign); 配对我想会让你做你想做的事

标签: javascript events removeeventlistener


【解决方案1】:

您可以使用元素的dataset 对象将string 类型的参数传递给事件处理程序。

显然,尝试在函数对象上放置参数只会覆盖同名的属性,并且.bind 方法不会返回调用它的函数。尝试在闭包中或通过调用 bind 传递参数将导致多个处理函数对象。

dataset 方法的未经测试示例:

[].forEach.call(signBoxes, (e, i) => {
  e.dataset.index = i;  // store index on element
  e.addEventListener("click", setSign);
});

function setSign() {
  const { name, src } = signs[this.dataset.index];; // lookup using index
  const sign = name;
  const Img = src;
  player1Choice.src = Img;
  [].forEach.call(signBoxes, (e, i) => {
    e.removeEventListener("click", setSign);
  });
  socket.emit("self-choose-sign", sign);
}

【讨论】:

  • 我能够提出不满意的解决方案,因为我只有 3 个元素,我检查了 event.path[1].id(DOM 元素的 ID)是否为 someValue,然后我会通过 setSign[correspondingValue]。这对我的长名单没有帮助。您的解决方案有效并且更好。甚至不必使用数据集,因为它也仅适用于 e.index
  • @Zobla 您通常可以将 HTMLElement 对象视为普通 JavaScript 对象并向其添加任何数据类型的新属性,从历史上看,这会导致问题并且不鼓励作为非标准.由于dataset 属性是在标准中定义的,因此它在未来仍然是可预测的。
猜你喜欢
  • 1970-01-01
  • 2018-09-04
  • 1970-01-01
  • 2022-08-03
  • 1970-01-01
  • 1970-01-01
  • 2011-03-07
  • 1970-01-01
  • 2023-03-29
相关资源
最近更新 更多