[英]Adding event Listener to elements on click of another in loop
我的打字稿项目有很烦人的问题。 没什么可看的,但出于某种原因,一旦我单击这 3 个菜单中的任何一个元素,onclick 执行的次数与特定菜单中的元素数量一样多,而不是每次单击一次。
我已经尝试了一段时间,因此在评论或不同的添加侦听器中,功能略有不同。
如何使这些 EventListeners 只执行一次在菜单中选择一个选项
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>
问题是事件传播之一(也称为“冒泡”,如链接的 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 动态添加,因此我看不出有任何理由不能在加载页面时直接将事件侦听器添加到每个输入。 这将导致更清晰和更简单的代码。
你写了:
每次单击menu1
,将一个新的 onClick 侦听器附加到他的每个孩子。
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);
}
});
}
});
只需替换为
let elements = menu1.querySelectorAll("input");
for(let i=0; i< elements.length; i++) {
let elem = elements[i]; //To avoid the common closure problem
elem.addEventListener("click", function () {
if (elem.checked) {
let val = elem.value;
dataSet.setEffect(elem.value);
console.log(dataSet);
}
});
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.