点击初始按钮后,如何让JS忽略该点击并等待指定类元素点击?
问题场景
点击标注为SELECT START NODE的按钮后,希望等待用户点击带有特定类名node的元素,但当前代码会捕获初始按钮的点击事件,导致后续对node元素的点击被忽略。
原代码
function waitingForNodeClick(){ return new Promise(resolve=>{ console.log("in promise") document.body.addEventListener('click',(event)=>{ const classClicked = event.target.className.split(" ")[0] console.log(event) if (classClicked==="node"){ resolve() } },{once: true}) }) } async function handleSetStart(){ console.log("waiting for click on any node") await waitingForNodeClick() console.log("clicked") }
<button onClick={handleSetStart}>SELECT START NODE</button>
运行输出
waiting for click on any node in promise click { target: button, buttons: 0, clientX: 916, clientY: 8, layerX: 916, layerY: 8 }
解决方法
问题根源是事件冒泡:按钮的点击事件会向上冒泡到document.body,被刚添加的监听器捕获;而监听器设置了{once: true},触发一次就会被移除,导致后续点击node元素时已无有效监听。
以下两种方式可解决该问题:
方式1:阻止按钮点击事件的冒泡
修改按钮的点击处理函数,在启动监听前阻止事件向上冒泡,避免document.body的监听器捕获这次点击:
async function handleSetStart(e){ e.stopPropagation(); // 阻止事件冒泡到body console.log("waiting for click on any node") await waitingForNodeClick() console.log("clicked") }
<button onClick={handleSetStart}>SELECT START NODE</button>
方式2:在body监听器中过滤按钮元素
如果不想修改按钮的事件逻辑,可在waitingForNodeClick的监听器里先判断点击目标是否为初始按钮,若是则直接跳过:
function waitingForNodeClick(){ return new Promise(resolve=>{ console.log("in promise") document.body.addEventListener('click',(event)=>{ // 过滤初始按钮,可根据按钮的id/class做更精准判断 if (event.target.tagName === 'BUTTON' && event.target.textContent.trim() === 'SELECT START NODE') { return; } const classClicked = event.target.className.split(" ")[0] console.log(event) if (classClicked==="node"){ resolve() } },{once: true}) }) }
建议给按钮添加唯一id(如id="select-start-btn"),通过event.target.id === 'select-start-btn'判断会更可靠。
内容的提问来源于stack exchange,提问作者Vedank Pande
相关产品推荐
相关产品推荐

