单击另一个in循环将事件侦听器添加到元素

时间:2020-11-04 20:48:23

标签: javascript html dom addeventlistener

我的打字稿项目有个很烦人的问题。别无所求,但由于某种原因,一旦我单击这3个菜单中的任何一个,onclick就会执行与特定菜单中元素数量相同的次数,而不是每次单击一次。

我已经尝试了一段时间,因此在注释或其他添加的侦听器中,功能有所不同。

如何使这些EventListener仅执行一次,方法是在菜单中选择一个选项

onst menu1 = document.getElementById("menu1") as HTMLDivElement;
const menu2 = document.getElementById("menu2") as HTMLDivElement;
const menu3 = document.getElementById("menu3") as HTMLDivElement;



menu1.addEventListener("click",  function () {

  let elements = menu1.querySelectorAll("input");
  for(let i=0; i< elements.length; i++) {
      elements[i].addEventListener("click", function () {
        if (elements[i].checked) {
          let val = elements[i].value;
          dataSet.setEffect(elements[i].value);
          console.log(dataSet);
        }
      });
    }
});


menu2.addEventListener("click", function(){

  const elements2 = menu1.querySelectorAll("label");
  // for (let element of elements2) {
  //   element.addEventListener("click", function () {
  //       dataSet.setEffect(element.value);
  //       console.log(dataSet);
  //   });
  // }
  elements2.forEach( function (ele,index) {
      // ele.addEventListener("click", function () {
      //         dataSet.setEffect(ele.innerText);
      //         console.log(dataSet);
      // });
  ele.onclick = function () {
    dataSet.setEffect(ele.innerText);
    console.log(dataSet,ele);
  }
  })

});


menu3.addEventListener("click", ()=>{
  let elements3 = menu3.children;
  for(let i=0; i< elements3.length; i++)
  {
    elements3[i].addEventListener("click", ()=>{
      dataSet.setBGC(elements3[i].id);
      console.log(dataSet);
    });
  }
});

html用于单个菜单

 <div class="container">
        <div class="header-text">
            <h2>Effect</h2>
        </div>
        <div class="select" id="menu1" tabindex="1">
            <input class="options-select"  value="solidColor" name="selectors1" type="radio" id="opt1" checked>
                <label for="opt1" class="option">Solid Color</label>
            <input class="options-select" value="EQCenter" name="selectors1" type="radio" id="opt2">
                <label for="opt2" class="option">EQ Center</label>
            <input class="options-select" value="Strobe" name="selectors1" type="radio" id="opt3">
                <label for="opt3" class="option">Strobe</label>
            <input class="options-select" value="Sparkel" name="selectors1" type="radio" id="opt4">
                <label for="opt4" class="option">Sparkel</label>
            <input class="options-select" value="swicth" name="selectors1" type="radio" id="opt5">
                <label for="opt5" class="option">Switch</label>
        </div>
        
    </div>

2 个答案:

答案 0 :(得分:0)

问题是事件propagation之一(也称为“冒泡”,如链接的MDN文章中所述)。每次点击input之一时,也会触发每个父元素上的事件。由于其中包括菜单本身,因此您的事件处理程序将再次运行-向每个项目添加更多事件侦听器。

要解决此问题,最简单的代码更改就是使用事件对象的内置stopPropagation方法来防止此问题:

  elements[i].addEventListener("click", function (event) {
    event.stopPropagation();
    if (elements[i].checked) {
      let val = elements[i].value;
      dataSet.setEffect(elements[i].value);
      console.log(dataSet);
    }
  });

但是,尽管这可以解决问题,但我强烈建议您考虑实现目标的不同方法。在另一个事件侦听器中添加一个事件侦听器基本上是一种反模式-它很容易导致出现您在此处遇到的问题,而我在考虑任何需要或有用的情况下都很难。由于您的输入就在HTML源代码中,而不是随Javascript动态添加,因此我看不出您为什么不能在加载页面时直接将事件侦听器直接添加到每个输入中的任何原因。这样可以使代码更简洁明了。

答案 1 :(得分:0)

您写道:

每次单击function applyFilters(counter) { if (counter >= filter.length) return Promise.resolve(true); const filter = filters[counter]; return applyStep(filter) .then(promiseTimeout(filter.delay)) .then(res => applyFilters(++counter)); } ,然后将新的onClick侦听器附加到他的每个孩子。

menu1

只需替换为

menu1.addEventListener("click",  function () {
  let elements = menu1.querySelectorAll("input");
  for(let i=0; i< elements.length; i++) {
      elements[i].addEventListener("click", function () {
        if (elements[i].checked) {
          let val = elements[i].value;
          dataSet.setEffect(elements[i].value);
          console.log(dataSet);
        }
      });
    }
});