我有一个小问题,我在下面的代码片段中复制了这个问题(以尽可能简单的方式,但它仍然显示了我所面临的问题)。
下面是片段:
const searchBar = document.getElementById('search');
const resBox = document.getElementById('results');
searchBar.addEventListener('input', function handler(e) {
if (e.target.value === '') {
resBox.innerHTML = '';
return false;
}
setTimeout(() => populate(e), 300);
});
function populate(e) {
const btnBox = document.createElement('div');
for (let i = 1; i <= 3; i++) {
const btn = document.createElement('button');
btn.classList.add('js-click')
btn.innerText = 'Click me';
btnBox.appendChild(btn);
}
resBox.appendChild(btnBox);
dynamicBtnClickListener();
}
function dynamicBtnClickListener() {
resBox.addEventListener('click', function handler(e) {
console.log('You clicked me !');
});
// THE SOLUTION I FOUND FOR THE MOMENT :
//const btns = document.querySelectorAll('button.js-click');
//btns.forEach(btn => {
// btn.addEventListener('click', function handler(e) {
// console.log('You clicked me !');
// });
//});
}<input type="text" id="search">
<div id="results"></div>
正如您在代码段中所看到的,我在输入上有第一个监听器,它在输入时生成一个按钮列表。当它是空的时候,按钮就会消失。在我的实际案例中,它是一个搜索输入,当用户输入它时,它调用一个函数,该函数用DB的结果填充它下面的结果框。
然后,我在按钮上有一个单击监听器。在代码片段中,我只需在单击按钮时放置一个控制台(“您单击了我”)。在我的实际应用程序中,它接受结果项(每个结果都是用户)并将其插入到表中。
打开、关闭、然后重新打开结果框时会出现问题。这是通过输入一些东西,清除输入,然后再输入一些东西来完成的.当您这样做,然后单击其中一个按钮时,它会在打开/关闭结果框时对其触发单击事件多次,因此您将在控制台上多次看到“您单击了我”。
我做了一些研究,其中大多数都要求使用event.stopPropagation()和/或删除事件侦听器。我确实尝试了所有这些可能的解决方案,以我所能想到的每一种方式,但我无法使它发挥作用。
不管怎样,我找到了一种解决这个问题的方法( dynamicBtnClickListener()函数的注释部分),但我觉得这不是最优的。它包括使用querySelectorAll()获取所有按钮,然后循环它们并将单击侦听器添加到每个按钮中,但我认为这不是最佳的,也不是最好的实践。这就是为什么我来这里询问是否有更好的解决方案,可能是保持结果框上的单击侦听器的解决方案(如果这是最理想的解决方案)。顺便问一下,是吗?
所以,即使我找到了解决这个问题的方法,能不能有人告诉我什么是最好的做法和最佳的方法?
非常感谢你的帮助
发布于 2021-02-22 23:12:50
每次输入文本区域时,每次都访问resBox,而实际元素resBox每次都会获得一个新的事件侦听器(按钮本身没有任何特定的侦听器,因此我让每个按钮都有一个特定的侦听器)。
const searchBar = document.getElementById('search');
const resBox = document.getElementById('results');
searchBar.addEventListener('input', function handler(e) {
if (e.target.value === '') {
resBox.innerHTML = '';
return false;
}
setTimeout(() => populate(e), 300);
});
function populate(e) {
const btnBox = document.createElement('div');
for (let i = 1; i <= 3; i++) {
const btn = document.createElement('button');
btn.classList.add('js-click')
btn.innerText = 'Click me';
btn.addEventListener('click',function(ev){console.log('You clicked me !')})
btnBox.appendChild(btn);
}
resBox.appendChild(btnBox);
}<input type="text" id="search">
<div id="results"></div>
现在,下面是一个示例,它只有一个事件侦听器,但是可以完全处理情况>:D
从技术上讲,这应该更快(因为一个事件侦听器与许多事件侦听器相比),但是个人我更喜欢这个选项,因为它“感觉更好”,因为一个函数控制了整个按钮布局(这会使它不那么“僵硬”)
PS:速度差太小了,你可以选择(但如果一整吨的按钮,是这样变得更好)
const searchBar = document.getElementById('search');
const resBox = document.getElementById('results');
const randChars=()=>{ //random characters to prove ONE event listener can work for multiple buttons in resBox
let arr=["a","b","c","d","e"]
let randIndex=()=>Math.floor(Math.random()*arr.length)||1
let n=randIndex(); let returnChar=""
for(let i=0;i<n;i++){returnChar+=arr[randIndex()]}
return returnChar
}
searchBar.addEventListener('input', function handler(e) {
if (e.target.value === '') {
resBox.innerHTML = '';
return false;
}
setTimeout(() => populate(e), 300);
});
resBox.addEventListener('click',function(ev){ //single event listener for all buttons
let currentButton=ev.path[0]
if(currentButton.tagName!="BUTTON"){return;} //if a button was not clicked
console.log("Button with text\n'"+currentButton.innerText+"'\nwas clicked")
})
function populate(e) {
const btnBox = document.createElement('div');
for (let i = 1; i <= 3; i++) {
const btn = document.createElement('button');
btn.classList.add('js-click')
btn.innerText = 'Click me '+randChars();
btnBox.appendChild(btn);
}
resBox.appendChild(btnBox);
}<input type="text" id="search">
<div id="results"></div>
https://stackoverflow.com/questions/66324679
复制相似问题