我无法理解何时/如何添加事件侦听器,并试图通过这个小片段来说明我的一般性问题。
如果切换按钮具有mousedown
事件,则小框在显示还是不显示之间切换。另外,如果显示了该文档,则对于文档中任何地方的mousedown
事件,该框将变为不显示。
我的问题是,如果evt.stopPropagation
被注释掉了,为什么不起作用?
如果.evt.stopPropagation
和document.addEventListener
都被注释掉了,则该切换将按预期方式工作,但仅对按钮有效,并且不会从文档中mousedown
的显示框中删除该框。
如果当文档上的事件侦听器处于活动状态并且clear
被注释掉时,如果console.log消息放在evt.stopPropagation
函数中,则可以看到mousedown
位于该按钮还会触发文档上的mousedown
。因此,单击切换按钮会同时显示并从显示中删除,并且永远不会看到该框。
我期望按钮事件在其自身的事件之后将事件侦听器添加到文档中,从而使文档无法为按钮上的第一个事件注册mousedown
事件,因为该事件尚未发生宣布但似乎两个侦听器是同时设置的。
能请您解释一下吗?谢谢您考虑我的问题。
"use strict";
document.querySelector('button').addEventListener( 'mousedown', display, false );
function display( evt )
{
evt.stopPropagation();
let e = evt.currentTarget.nextElementSibling;
if ( e.style.display === 'block' )
{
e.style.display = 'none';
}
else
{
e.style.display = 'block';
document.addEventListener( 'mousedown', clear, false );
}; // end if
} // close display
function clear()
{
document.removeEventListener( 'mousedown', clear, false );
document.querySelector('button').nextElementSibling.style.display = 'none';
}
div {
display: none;
background-color: rgb(150,150,150);
border: 1px solid black;
height: 50px;
width: 50px;
margin-top: 10px;
}
<button>Toggle</button>
<div></div>
答案 0 :(得分:0)
在bubbling phase中,事件使DOM从生成事件的目标元素经过元素链的父节点链上升到document
对象,然后从那里到达{{1} }:
在处理程序中调用window
会阻止事件在DOM上继续冒泡(当然)。
现在,如果未显示切换的下一个同级,则event.stopPropagation
事件处理程序将停止传播,显示下一个元素,并在文档节点上注册一个侦听器以再次隐藏该元素。
如果未调用display
,则stopPropagation
事件会继续使DOM冒泡,以寻找要调用的“ mousedown”侦听器。它会找到{{ 1}}到文档节点(即“清除”函数),对其进行调用,并且处理程序的执行将隐藏切换后的下一个元素。
在为mousedown
和display
调用mousedown
处理程序之间,以及处理事件冒泡阻止屏幕更新之间的短暂时间内,您永远都看不到下一个元素永远不会。
答案 1 :(得分:0)
@ traktor53的答案正确地确定了会发生什么,但我担心他们的解释还不够清楚。
您在这里遇到的事情基本上是由两个事实造成的:
为了更好地理解,我现在将避免谈论捕获阶段。
因此,当浏览器要在目标上分配事件时,它将首先检查它必须在该目标上调用的所有处理程序,然后执行所有这些处理程序,最后将DOM冒泡到窗口中(当然,仅在发生冒泡事件的情况下。
以您的示例为例,我们可以将此冒泡阶段进行模式化:
[<button>] -> list of handlers: [`ƒ display`]
execute `ƒ display` // (add handler on document)
continue with parentNode
[<body>] -> list of handlers: none
continue with parentNode
[<html>] -> list of handlers: none
continue with ownerDocument
[document] -> list of handlers: [`ƒ clear`] // (added in `display`)
execute `ƒ clear`
continue with defaultView
[window] -> list of handlers: none
您可以看到,之前添加了您在document
上添加的EventHandler,该算法必须检查附加到document
上的EventHandler。因此,当要在document
EventTarget上触发Event时,后者将为其附加此EventHandler。
为了演示它,我们甚至可以构建此梯形图代码,该代码将从第一个EventHandler内部将EventListener添加到原始目标的所有祖先:
document.querySelector('button').addEventListener('mousedown', handle, {once:true});
function handle(evt) {
console.log('firing from', this.toString());
const up = this.defaultView || // window for document
this.parentNode || // elements until html
this.ownerDocument; // html
if(up) up.addEventListener('mousedown', handle, {once:true});
}
<button>click me</button>
这样做,您的clear
函数将在display
被调用后立即被调用,并立即恢复display
所做的事情。