简而言之,我在addEventListener
中有addEventListener
。我正在听的事件是click
。这是我的代码示例:
function toggleElement() {
// function stuff
}
anchor.addEventListener('click', (e) => {
e.preventDefault();
if (!anchorWrapper.classList.contains('active')) {
// do some stuff
window.addEventListener('click', toggleElement, false);
} else {
// do some stuff
window.removeEventListener('click', toggleElement, false);
}
});
每次单击锚元素时,我都会将一个事件侦听器分配给侦听单击的窗口。我希望用户单击锚点,锚点又不应初始化toggleElement
,而只是将事件侦听器分配给窗口。然后,根据我的想法(事实证明是错误的),应仅在下次在窗口的任何位置第二次单击时才初始化该函数。但是,它是通过单击锚元素来运行的。
我不正确是什么?如何防止用户单击锚元素时toggleElement
函数未初始化,而是等待窗口上的click
事件?
答案 0 :(得分:2)
问题在于,您的第一个事件是从DOM到propagating,直到您刚刚向其添加事件处理程序的节点(在您的情况下是窗口)。因为传播将在回调退出后继续进行,这意味着添加第二个事件处理程序后,它将触发第二个事件处理程序。
您可以通过在事件中使用stopPropagation
方法来避免这种情况。您还可以使用其他技术(例如promise或零长度超时)将其释放给引擎中的下一个JS“任务”,但是还有一些您不想这样做的原因。
我在这里创建了一些示例代码,它还处理了您希望按钮(或其他按钮)内的后续单击也触发第二个事件处理程序的情况。还要注意,我正在让第二个事件处理程序注销自己,这使此逻辑稍微简单一些。
let target = document.getElementById("target");
let targetWrapper = document.getElementById("targetWrapper");
function secondFunction() {
console.log("Called second callback");
//alert("Second Function Called");
targetWrapper.removeEventListener('click', secondFunction, false);
targetWrapper.classList.remove("active");
}
target.addEventListener('click', (e) => {
console.log("Called first callback")
e.preventDefault();
if(!targetWrapper.classList.contains("active")){
targetWrapper.addEventListener('click', secondFunction, false);
targetWrapper.classList.add("active");
e.stopPropagation();
}
});
body {
font-size: 20px;
font-family:sans-serif;
}
#targetWrapper {
min-height: 400px;
min-width: 400px;
text-align: center;
background-color: green;
position:relative;
}
#target {
vertical-align: middle;
background-color:blue;
color:red;
padding:50px;
position:absolute;
top:100px;
left:50px;
}
#targetWrapper.active{
outline: 3px solid red;
}
<div id="targetWrapper">
<a id="target">
Click me!
</a>
</div>
有关事件传播和处理程序的更多信息:
答案 1 :(得分:1)
toggleElement是否获得“旧”点击事件?尝试将其设置为零超时:
setTimeout(function() { window.addEventListener('click', toggleElement, false); });
答案 2 :(得分:1)
也许代码比您的点击更快?我认为单击时会分配事件侦听器,但您仍在“单击”,因此第二个事件侦听器也会检测到该单击。如果我错了请纠正我。
尝试将e.stopPropagation();
放在e.preventDefault();
之后。