Javascript 即使在事件发生后定义,也会执行事件处理程序

Javascript 即使在事件发生后定义,也会执行事件处理程序,javascript,Javascript,考虑以下代码: function something(){ ... document.addEventListener('click', clickHandler); } function clickHandler(e) {...} 单击我的页面中的图标时,将调用某个()。因此,通过单击该图标,clickHandler()也将被执行。这是完全无法解释的,因为事件侦听器是在之后添加的。 有什么好主意吗?你的答案在问题的第一行: something()在单击内部现有的图标时被调用 我的页

考虑以下代码:

function something(){
  ...
  document.addEventListener('click', clickHandler);
}

function clickHandler(e) {...}
单击我的页面中的图标时,将调用某个
()。因此,通过单击该图标,
clickHandler
()也将被执行。这是完全无法解释的,因为事件侦听器是在之后添加的。
有什么好主意吗?

你的答案在问题的第一行:

something()
在单击内部现有的图标时被调用 我的页面

因此,您必须已经设置了图标的
单击处理程序
以使该行为正常工作。这意味着每次单击图标时,您都会触发由
某物
处理的
单击
事件,但您也会为
文档注册一个完全不同的
单击
事件处理程序

由于事件冒泡,任何单击图标(位于
文档
中)都将触发该元素的
单击事件处理程序(
某物
),然后事件将冒泡到
文档
,该文档将触发其
单击事件处理程序(
单击事件处理程序

所以这里没有什么不符合顺序的。这是一个简单的事件处理程序设置另一个事件处理程序的情况,因为第一个处理程序在第二个处理程序接收事件之前被调用,所以第二个绑定会及时发生,以便
文档
处理冒泡事件

下面是您的代码(为了运行而稍微修改),并附有注释:

document.querySelector(“div”).addEventListener(“单击”,某物);
函数某物{
log(“由于单击了div,所以调用了函数something”);
//每次单击div时,都会在文档中启动一个click事件
//这将向上传播到文档本身,并设置下一行
//该级别的处理程序:
document.addEventListener('click',clickHandler);
}
函数clickHandler(e){
console.log(e.type+”由文档级处理的“+e.target+”触发);
}
div{背景色:#800080;颜色:橙色;}
首先,单击紫色div之外的任何位置,都不会发生任何事情,因为
最初为它设置了单击事件的是div。然后单击div,您将看到
不仅让div的事件处理程序运行,而且因为该处理程序设置了click事件
文档和事件的处理程序还没有出现,您将得到相同的结果
再次单击事件处理,但按文档处理。

然后,再次单击div外部。因为文档现在已经设置了事件处理程序 对于它,单击将在那里处理。


单击我。
当您添加此处理程序以便调用它时,似乎仍在为当前事件调用处理程序,将useCapture值设置为true似乎会停止它

function something(){
  ...
  document.addEventListener('click', clickHandler, true);
}
useCapture可选
一个布尔值,指示在将此类型的事件分派到DOM树中其下的任何EventTarget之前,是否将其分派到已注册的侦听器。通过树向上冒泡的事件不会触发指定使用捕获的侦听器。事件冒泡和捕获是两种传播发生在嵌套在另一个元素中的元素中的事件的方法,当两个元素都为该事件注册了句柄时。事件传播模式确定元素接收事件的顺序。有关详细说明,请参见DOM级别3事件和JavaScript事件顺序。如果未指定,useCapture默认为false


如果再次单击该图标,是否执行了两次
clickHandler()
。它被执行了。您正在
文档
上注册一个侦听器,无论您单击哪个元素,都会调用该侦听器。@DanO事件只会向上冒泡。他们被俘虏了@DanO同样,这并不能解释为什么处理程序会被调用两次(除非在图标上也设置了另一个处理程序)。冒泡有助于事件绑定,但不会影响事件的触发次数。如果愿意,还可以使用
stopPropagation()
显式阻止事件继续冒泡。在添加事件监听器(无论您需要在哪里添加它…)后,您将阻止当前事件触发它。由于并非所有事件都可以在捕获阶段处理,而且IE早期不支持它,因此它没有得到广泛使用或超级有用
stopPropagation()
将解决此问题。但实际上,您的答案并没有首先说明为什么会发生这种情况。很明显,“为什么会发生这种情况”。代码在事件发生的位置添加了一个事件处理程序,该事件会继续传播到可能感兴趣的每一段代码中,触发刚刚添加的处理程序,因为它被添加到事件传播步行器尚未访问的对象。@MikeRobinson您和我可能都很清楚,但问题被问到这一事实意味着OP和其他人不清楚。因此,任何“答案”都应该解决这个问题。