简体   繁体   English

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

[英]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);
    }
   });
}

难以将唯一的事件侦听器添加到已创建的<div>通过 for 循环的元素</div><div id="text_translate"><p>我正在做一个项目来学习一些 JavaScript,目标是在单页 web 应用程序中动态提供电子邮件。 应用程序的HTML已经使用createElement JS方法创建。 到目前为止,我已经成功地显示了包含所有电子邮件的“收件箱”页面,如下图所示:</p><p> <a href="https://i.stack.imgur.com/V8cZq.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/V8cZq.png" alt=""></a></p><p> 我目前正在尝试通过使用 addEventListener 使这些单独的电子邮件中的每一个都可以点击。 我遇到的问题是,每当我单击任何一封电子邮件时,都会呈现收件箱中的第一个 email(id:1,主题:测试电子邮件),并且无法查看任何其他电子邮件。</p><p> <a href="https://i.stack.imgur.com/BBjQj.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/BBjQj.png" alt=""></a></p><p> 我可以看到相同的 email.id 被应用到所有创建的 div 的事件侦听器,尽管所有 div 都被正确创建,并包含来自相应电子邮件的所有信息。</p><p> 这是加载邮箱 JS,它呈现收件箱中的所有电子邮件:</p><pre> function load_mailbox(mailbox) { // Show the mailbox and hide other views document.querySelector('#emails-view').style.display = 'block'; document.querySelector('#compose-view').style.display = 'none'; document.querySelector('#single-view').style.display = 'none'; // Show the mailbox name document.querySelector('#emails-view').innerHTML = `<h3>${mailbox.charAt(0).toUpperCase() + mailbox.slice(1)}</h3>`; // GET request fetch(`/emails/${mailbox}`).then(response => response.json()).then(emails => { // Print emails to console console.log(emails); // Iterate through each email for(var i = 0; i < emails.length; i++) { var email = emails[i]; // Create div and append email content to HTML var emaildiv = document.createElement('div'); emaildiv.style.borderStyle = 'solid'; emaildiv.style.borderColor = 'black'; emaildiv.style.borderWidth = '0.1rem'; emaildiv.style.borderRadius = '0'; emaildiv.style.marginBottom = '0.2rem'; emaildiv.style.padding = '0.3rem'; emaildiv.innerHTML = `<b>${email.sender}</b> --- ${email.subject}<br>${email.timestamp}`; // If individual email selected then view email emaildiv.addEventListener('click', () => view_email(email)); // Populate div HTML with emails document.querySelector('#emails-view').append(emaildiv); console.log(email.read); // Colour backgrounds based on whether emails have been read if (email.read == true) { emaildiv.style.backgroundColor = 'lightgrey'; } console.log(email); } });}</pre><p> 这是视图 email JS,它应该渲染个人 email 的 HTML:</p><pre> // View email function view_email(email) { console.log(email.id); // Show the mailbox and hide other views document.querySelector('#emails-view').style.display = 'none'; document.querySelector('#compose-view').style.display = 'none'; document.querySelector('#single-view').style.display = 'block'; // GET request fetch(`/emails/${email["id"]}`).then(response => response.json()).then(email => { // Create div, set class, and append email content to HTML var reademail = document.createElement('div'); reademail.innerHTML = ''; reademail.style.borderStyle = 'solid'; reademail.style.borderColor = 'black'; reademail.style.borderWidth = '0.1rem'; reademail.style.borderRadius = '0'; reademail.style.marginBottom = '0.2rem'; reademail.style.padding = '0.3rem'; reademail.innerHTML = ` <b>From:</b> ${email.sender}<br> <b>To:</b> ${email.recipients}<br> <b>Subject:</b> ${email.subject}<br> <b>Timestamp:</b> ${email.timestamp}<br> <button class="btn btn-sm btn-outline-primary" id="Reply">Reply</button> <hr> ${email.body}`; // Populate div HTML with emails document.querySelector('#single-view').append(reademail); // Mark unread emails as read if (email.read === 'false') { fetch(`/emails/${email}`, { method: 'PUT', body: JSON.stringify({ read: true }) }) } }); }</pre><p> 这是存储在 email GET 响应中的示例(虚拟数据):</p><pre> { "id": 1, "sender": "user@example.com", "recipients": ["user@example.com"], "subject": "Hello,": "body", "Hello, world:", "timestamp": "Oct 24 2020, 12:00 AM", "read": false, "archived": false }</pre><p> 我已经尝试将其他每封电子邮件的 ID 硬编码到视图 email JS 中,并且可以看到该功能按要求工作(显示电子邮件)。</p><p> 因此,我知道问题与上面的加载邮箱 JS 有关,并且可能与事件侦听器如何在 for 循环中应用有关。 如果有人可以阐明如何将唯一的事件侦听器应用于每个单独的 div,将不胜感激。</p><p> 谢谢!</p></div> - Difficulty adding unique event listener to created <div> elements via a for loop

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 向具有相同类的元素添加单击事件侦听器 - Adding click event listener to elements with the same class 使用“ for”循环添加“ click”事件监听器 - Adding 'click' event listener using 'for' loop 点击循环事件监听器 - Event listener on click on loop 向所有元素添加单击事件侦听器-Firefox附加组件 - adding a click event listener to all elements - Firefox Add-on 难以将唯一的事件侦听器添加到已创建的<div>通过 for 循环的元素</div><div id="text_translate"><p>我正在做一个项目来学习一些 JavaScript,目标是在单页 web 应用程序中动态提供电子邮件。 应用程序的HTML已经使用createElement JS方法创建。 到目前为止,我已经成功地显示了包含所有电子邮件的“收件箱”页面,如下图所示:</p><p> <a href="https://i.stack.imgur.com/V8cZq.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/V8cZq.png" alt=""></a></p><p> 我目前正在尝试通过使用 addEventListener 使这些单独的电子邮件中的每一个都可以点击。 我遇到的问题是,每当我单击任何一封电子邮件时,都会呈现收件箱中的第一个 email(id:1,主题:测试电子邮件),并且无法查看任何其他电子邮件。</p><p> <a href="https://i.stack.imgur.com/BBjQj.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/BBjQj.png" alt=""></a></p><p> 我可以看到相同的 email.id 被应用到所有创建的 div 的事件侦听器,尽管所有 div 都被正确创建,并包含来自相应电子邮件的所有信息。</p><p> 这是加载邮箱 JS,它呈现收件箱中的所有电子邮件:</p><pre> function load_mailbox(mailbox) { // Show the mailbox and hide other views document.querySelector('#emails-view').style.display = 'block'; document.querySelector('#compose-view').style.display = 'none'; document.querySelector('#single-view').style.display = 'none'; // Show the mailbox name document.querySelector('#emails-view').innerHTML = `<h3>${mailbox.charAt(0).toUpperCase() + mailbox.slice(1)}</h3>`; // GET request fetch(`/emails/${mailbox}`).then(response => response.json()).then(emails => { // Print emails to console console.log(emails); // Iterate through each email for(var i = 0; i < emails.length; i++) { var email = emails[i]; // Create div and append email content to HTML var emaildiv = document.createElement('div'); emaildiv.style.borderStyle = 'solid'; emaildiv.style.borderColor = 'black'; emaildiv.style.borderWidth = '0.1rem'; emaildiv.style.borderRadius = '0'; emaildiv.style.marginBottom = '0.2rem'; emaildiv.style.padding = '0.3rem'; emaildiv.innerHTML = `<b>${email.sender}</b> --- ${email.subject}<br>${email.timestamp}`; // If individual email selected then view email emaildiv.addEventListener('click', () => view_email(email)); // Populate div HTML with emails document.querySelector('#emails-view').append(emaildiv); console.log(email.read); // Colour backgrounds based on whether emails have been read if (email.read == true) { emaildiv.style.backgroundColor = 'lightgrey'; } console.log(email); } });}</pre><p> 这是视图 email JS,它应该渲染个人 email 的 HTML:</p><pre> // View email function view_email(email) { console.log(email.id); // Show the mailbox and hide other views document.querySelector('#emails-view').style.display = 'none'; document.querySelector('#compose-view').style.display = 'none'; document.querySelector('#single-view').style.display = 'block'; // GET request fetch(`/emails/${email["id"]}`).then(response => response.json()).then(email => { // Create div, set class, and append email content to HTML var reademail = document.createElement('div'); reademail.innerHTML = ''; reademail.style.borderStyle = 'solid'; reademail.style.borderColor = 'black'; reademail.style.borderWidth = '0.1rem'; reademail.style.borderRadius = '0'; reademail.style.marginBottom = '0.2rem'; reademail.style.padding = '0.3rem'; reademail.innerHTML = ` <b>From:</b> ${email.sender}<br> <b>To:</b> ${email.recipients}<br> <b>Subject:</b> ${email.subject}<br> <b>Timestamp:</b> ${email.timestamp}<br> <button class="btn btn-sm btn-outline-primary" id="Reply">Reply</button> <hr> ${email.body}`; // Populate div HTML with emails document.querySelector('#single-view').append(reademail); // Mark unread emails as read if (email.read === 'false') { fetch(`/emails/${email}`, { method: 'PUT', body: JSON.stringify({ read: true }) }) } }); }</pre><p> 这是存储在 email GET 响应中的示例(虚拟数据):</p><pre> { "id": 1, "sender": "user@example.com", "recipients": ["user@example.com"], "subject": "Hello,": "body", "Hello, world:", "timestamp": "Oct 24 2020, 12:00 AM", "read": false, "archived": false }</pre><p> 我已经尝试将其他每封电子邮件的 ID 硬编码到视图 email JS 中,并且可以看到该功能按要求工作(显示电子邮件)。</p><p> 因此,我知道问题与上面的加载邮箱 JS 有关,并且可能与事件侦听器如何在 for 循环中应用有关。 如果有人可以阐明如何将唯一的事件侦听器应用于每个单独的 div,将不胜感激。</p><p> 谢谢!</p></div> - Difficulty adding unique event listener to created <div> elements via a for loop 使用for循环并传递不同的参数将事件侦听器添加到多个元素 - Adding event listener to multiple elements using for loop and passing different parameters 在具有循环和jQuery的同一类的所有元素上添加Click事件 - Adding Click event on all elements with the same class without loop and jQuery 如何将点击事件监听器添加到每个元素? - How to add click event listener to each elements? 附加到一键事件侦听器的多个元素 - multiple elements attached to one click event listener 在脚本中添加点击事件监听器不起作用 - Adding a click event listener in script not working
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM