首页 > 解决方案 > 将事件监听器添加到 foreach 循环中的每个项目

问题描述

I have a node list in a variable 

    connectedAnalysis = document.querySelectorAll('.connAnalysisUl li')

each li represents some text which I want to be removed when clicked on that li tag. 

I have code like this 

    connectedAnalysis.forEach((item) => {
       item.addEventListener('click', (e) => {
           e.preventDefault()
           console.log(item)
          })
       })

然后我注意到一些奇怪的行为。如果我的节点列表中有 3 个元素,并且如果我单击第一个元素,我将获得 3 次控制台日志,如果我单击第二个 li,我将获得两次控制台日志。所以在我继续之前,我想了解为什么会发生这种情况以及如何防止这种情况发生。我阅读了很多关于事件传播等的内容,但没有什么能帮助我理解我在这里面临的情况。我想要的是,如果我单击任何项​​目,它只会被触发一次。

这是完整的代码

    //here I'm defining some variables

 let connectedAnalysis = document.getElementById('connectedAnalysis')
 let getAnalyisisNameDiv = document.getElementById('resultConnectedAnalysis')
 let relatedAnalysisParent = document.getElementById('relatedAnalysis')
 let parentUl = document.querySelector('.connAnalysisUl')

    //here I'm listening for users input and then I query mongoDB collection, I'm displaying all the result as li items

connectedAnalysis.addEventListener('input', (e) => {
      if (connectedAnalysis.value.length > 2) {
      fetch('/analysis/'+e.target.value).then((data) => {
        data.json().then((result) => {
          getAnalyisisNameDiv.innerHTML = ''
          for(i=0; i<result.length; i++) {
            let liItem = document.createElement('li')
            liItem.className +="list-group-item"
            let link = document.createElement('a')
            link.href=result[i]._id
            liItem.appendChild(link)
            let analysisName = document.createTextNode(result[i].analysisName)
            link.appendChild(analysisName)
            getAnalyisisNameDiv.appendChild(liItem)
          } // for end

//here I would like to take all li tags inside my ul tag and when the user clicks on li item I would like to add it to the DOM

let analysisNameList = document.querySelectorAll('#resultConnectedAnalysis li')

            analysisNameList.forEach((item) =>  {
              item.addEventListener('click', (e) => {
                e.preventDefault()

                // creating hidden input tag and grab analysis id
                let connectedAnalysisID = document.createElement('input')
                connectedAnalysisID.type = 'hidden'
                connectedAnalysisID.name = 'connectedTo[]'
                connectedAnalysisID.setAttribute('value', e.srcElement.attributes.href.textContent)

//here I'm creating a remove button
                let removeButton = document.createElement('small')
                removeButton.className += 'ml-1 float-right removeConnectedAnalysis'
                let removeText = document.createTextNode('x')
                removeButton.appendChild(removeText)

//here I'm creating li tag and adding everything to the DOM

                let connectedAnalysisLi = document.createElement('li')
                connectedAnalysisLi.className += 'list-inline-item __connectedAnalysis'
                let connectedAnalysisInnerText = document.createTextNode(e.target.innerText)
                connectedAnalysisLi.appendChild(connectedAnalysisInnerText)
                connectedAnalysisLi.appendChild(removeButton)
                connectedAnalysisLi.appendChild(connectedAnalysisID)
                connectedAnalysisLi.appendChild(connAnalysisName)
                parentUl.appendChild(connectedAnalysisLi)
                relatedAnalysisParent.appendChild(parentUl)

  //here I would like to remove item which is added by the user
                let removeConnectedAnalysis = document.querySelectorAll('.connAnalysisUl li')

        removeConnectedAnalysis.forEach((item) => {
          item.addEventListener('click', (e) => {
            e.preventDefault()
              item.remove()
          })
        })

                  })// addeventlistener end
                })// analysisNameList end
            })// datajson end
          })// fetch end
        } else {
            getAnalyisisNameDiv.innerHTML = ''
          }
        })// connectedAnalysis event listener end

我相信我迷失在循环和范围以及我正在尝试学习的其他一些东西中。如果您能帮助我更好地理解我的错误,我将非常感激。谢谢

标签: javascriptforeachaddeventlistener

解决方案


最好使用事件委托,在所有元素的祖先中设置一个事件处理程序,这些元素可以触发事件并允许事件冒泡到该祖先。然后,在单个事件处理程序中,检查哪个元素触发了事件(如果需要)并采取行动。

这是您所说的尝试做的一个示例:

// Get a reference to the ancestor
let parent = document.querySelector(".parent");

// Set up a click event on the ancestor
parent.addEventListener("click", function(event){
  // Remove the element that triggered the event in the first place
  parent.removeChild(event.target);
});
<ul class="parent">
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
  <li>Item 4</li>
  <li>Item 5</li>
  <li>Item 6</li>
  <li>Item 7</li>
  <li>Item 8</li>   
</ul>


推荐阅读