Consider the following code:
function something(){
...
document.addEventListener('click', clickHandler);
}
function clickHandler(e) {...}
当单击页面内部存在的图标时,会调用something
()。因此,单击该图标时,clickHandler
()也会被执行。这完全无法解释,因为事件监听器是在之后添加的。
有什么好的想法吗?
Consider the following code:
function something(){
...
document.addEventListener('click', clickHandler);
}
function clickHandler(e) {...}
当单击页面内部存在的图标时,会调用something
()。因此,单击该图标时,clickHandler
()也会被执行。这完全无法解释,因为事件监听器是在之后添加的。
有什么好的想法吗?
something()
。”something
设置为图标的click
处理程序,以便该行为能够正常工作。这意味着每次单击图标时,都会触发由something
处理的click
事件,但是你还会为document
注册完全不同的click
事件处理程序。document
中)都会触发该元素的click
事件处理程序(something
),然后事件会冒泡到document
,它将触发其自己的click
事件处理程序(clickHandler
)。document
处理冒泡事件。document.querySelector("div").addEventListener("click", something);
function something(){
console.log("function something has been invoked because the div was clicked");
// Every time you click the div, you initiate a click event WITHIN the document
// that will propogate upward to the document itself and the next line sets up
// a handler at that level:
document.addEventListener('click', clickHandler);
}
function clickHandler(e) {
console.log(e.type + " triggered by: " + e.target + " handled at the document level");
}
div { background-color:#800080; color:orange;}
<p>First, click anywhere outside of the purple div and nothing will happen because the only thing
that initially has a click event set up for it is the div. Then click on the div and you'll
not only get the div's event handler to run, but because that handler sets up a click event
handler for the document and the event hasn't bubbled up there yet, you'll get that same
click event handled again, but by the document.
</p>
<p>
Then, click outside of the div again. Because the document now has an event handler set up
for it, the click will be handled there.
</p>
<div>Click me.</div>
event.stopPropagation()
停止事件进一步冒泡(从而防止它到达文档):
document.querySelector("div").addEventListener("click", something);
function something(e){
// Handle the event here but don't allow it to go anywhere else
e.stopPropagation();
console.log("function something has been invoked because the div was clicked");
// Every time you click the div, you initiate a click event WITHIN the document
// that will propogate upward to the document itself and the next line sets up
// a handler at that level:
document.addEventListener('click', clickHandler);
}
function clickHandler(e) {
console.log(e.type + " triggered by: " + e.target + " handled at the document level");
}
div { background-color:#800080; color:orange;}
<p>First, click anywhere outside of the purple div and nothing will happen because the only thing
that initially has a click event set up for it is the div. Then click on the div and you'll
not only get the div's event handler to run, but because that handler sets up a click event
handler for the document and the event hasn't bubbled up there yet, you'll get that same
click event handled again, but by the document.
</p>
<p>
Then, click outside of the div again. Because the document now has an event handler set up
for it, the click will be handled there.
</p>
<div>Click me.</div>
event.target
可以访问该元素:
// All clicks will eventually bubble up to the document
document.addEventListener('click', clickHandler);
function clickHandler(e) {
console.log(e.type + " triggered by: " + e.target + " handled at the document level");
// You can handle the event differently based on which element triggered it.
if(e.target.classList.contains("notSpecial")){
e.target.classList.add("special");
}
}
.special { background-color:red; }
.as-console-wrapper { max-height: 1.5em !important; }
<h1>click me</h1>
<p>No, click me!</p>
<div>What about me?!</div>
<div class="notSpecial">Click me. I'm special</div>
当你添加了这个处理程序后,似乎当前事件的处理程序仍然会被调用,设置useCapture值为true似乎可以阻止它。
function something(){
...
document.addEventListener('click', clickHandler, true);
}
useCapture 可选参数
一个布尔值,指示此类型的事件是否会在分派给 DOM 树中位于其下方的任何 EventTarget 之前分派给已注册的侦听器。通过树向上冒泡的事件不会触发使用捕获的侦听器。事件冒泡和捕获是在一个元素嵌套在另一个元素内部时,当这两个元素都为该事件注册了处理程序时,传播事件的两种方式。事件传播模式确定元素接收事件的顺序。有关详细说明,请参阅 DOM Level 3 Events 和 JavaScript Event order。如果未指定,则 useCapture 默认为 false。stopPropagation()
来明确地阻止事件继续冒泡。在添加事件监听器之后(无论你需要在哪里添加它...),你可以防止当前事件触发它。 - Mike RobinsonstopPropagation()
可以解决这个问题。但实际上,你的回答并没有解释为什么会出现这种情况。 - Scott Marcus
clickHandler()
会执行两次吗? - Klaycondocument
上注册一个监听器时,无论你点击哪个元素,它都会被调用。 - Dan O