[英]Adding event Listener to elements on click of another in loop
I have quite annoying problem with my typescript projekt.我的打字稿项目有很烦人的问题。 Nothing to fancy but for some reason once i click one of the elements in any of these 3 menus the onclick is executed as many times as the number of elements in particular menu instead of just once per click.
没什么可看的,但出于某种原因,一旦我单击这 3 个菜单中的任何一个元素,onclick 执行的次数与特定菜单中的元素数量一样多,而不是每次单击一次。
Ive been trying for some time therefore in comments or in different adding Listeners the functions differs a bit.我已经尝试了一段时间,因此在评论或不同的添加侦听器中,功能略有不同。
How to make these EventListeners to execute only one time choosing an option in the menu如何使这些 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 for a single menu单个菜单的 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>
The problem is one of event propagation (also called "bubbling", as in the linked MDN article).问题是事件传播之一(也称为“冒泡”,如链接的 MDN 文章中所述)。 Each time a click on one of the
input
s happens, it also triggers the event on each parent element.每次单击
input
的一个时,它也会触发每个父元素上的事件。 Since this includes the menu itself, your event handler for that runs again - adding further event listeners to each item.由于这包括菜单本身,您的事件处理程序再次运行 - 为每个项目添加更多事件侦听器。
The simplest code change to fix this is simply to use the built-in stopPropagation
method of the event object to prevent this:解决这个问题的最简单的代码更改就是使用事件对象的内置
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);
}
});
However, while this should fix the problem, I strongly encourage you to have a think about different ways to achieve your aim.但是,虽然这应该可以解决问题,但我强烈建议您考虑实现目标的不同方法。 Adding an event listener inside another event listener is basically an anti-pattern - it can easily lead to issues like the one you had here, and I'm struggling to think of any cases where it's needed or useful.
在另一个事件侦听器中添加一个事件侦听器基本上是一种反模式 - 它很容易导致像你在这里遇到的问题,我正在努力思考任何需要或有用的情况。 Since your inputs are right there in the HTML source, rather than dynamically added with Javascript, I don't see any reason why you couldn't simply add the event listeners to each input directly when the page is loaded.
由于您的输入就在 HTML 源代码中,而不是使用 Javascript 动态添加,因此我看不出有任何理由不能在加载页面时直接将事件侦听器添加到每个输入。 That would lead to cleaner and simpler code.
这将导致更清晰和更简单的代码。
You wrote:你写了:
each time menu1
is clicked, then attach a new onClick listener to each of his children.每次单击
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);
}
});
}
});
Just replace with只需替换为
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.