在 JS 中,您并不能真正控制调用事件处理程序的顺序,但是通过仔细的委派和适当的侦听器,这是可能的。
委托是事件模型最强大的功能之一。你可能知道也可能不知道:在 JS 中,一个事件被传递到 dom 的顶部,从那里它向下传播到应该应用事件的元素。因此,有理由认为,附加到全局对象的事件侦听器将在已附加到元素本身的侦听器之前调用其处理程序。
window.addEventListener('click',function(e)
{
e = e || window.event;
var target = e.target || e.srcElement;
console.log('window noticed you clicked something');
console.log(target);//<-- this is the element that was clicked
}, false);//<-- we'll get to the false in a minute
重要的是要注意我们实际上可以访问处理程序中的事件对象。在这种情况下,我们让事件对象保持不变,所以它会继续向下传播到目标,在向下传播的过程中,它可能会遇到这样的事情:
document.getElementById('container').addEventListener('click', function(e)
{
e = e || window.event;
var target = e.target || e.srcElement;
if (target.tagName.toLowerCase() !== 'a' || target.className.match(/\bclickable\b/))
{
return e;//<return the event, unharmed
}
e.returnValue = false;
if (e.preventDefault)
{
e.preventDefault();
}
}, false);
现在,该处理程序将在窗口级别的侦听器调用其帮助程序之后被调用。这一次,如果单击的元素没有类,或者该元素是链接,则更改事件。clickable
该活动被取消,但它仍然存在。该事件仍然可以自由地在 dom 中进一步传播,所以我们可能会遇到类似的情况:
document.getElmentById('form3').addEventListener('click',function(e)
{
e = e || window.event;
if (e.returnValue === false || e.isDefaultPrevented)
{//this event has been changed already
//do stuff, like validation or something, then you could:
e.cancelBubble = true;
if (e.stopPropagation)
{
e.stopPropagation();
}
}
}, false);
在这里,通过调用stopPropagation
,事件被终止。除非事件已被更改,否则它无法在 dom 中进一步传播到其目标。如果没有,事件对象会沿着 DOM 向下传播,就好像什么都没发生一样。
一旦它到达它的目标节点,事件就会进入它的第二个阶段:泡沫阶段。它没有向下传播到 DOM 的深处,而是向上爬回顶层(一直到全局对象,它被调度的地方......它从哪里来等等)。
在冒泡阶段,所有相同的规则都适用于传播阶段,只是相反。事件对象将首先遇到最接近目标元素的元素,最后遇到全局对象。
这里有很多方便且清晰的图表。我不能说它比好的 'ol quirksmode 更好,所以我建议你阅读他们在那里所说的内容。
底线:在处理 2 个事件侦听器时,将它们都附加到不同的级别,以便按照您喜欢的方式对它们进行排序。
如果您想保证两者都被调用,只需停止事件在最后调用的处理程序中传播。
当你有两个监听器,为同一个事件附加到同一个元素/对象时,我从来没有遇到过第一个附加的监听器没有被第一个调用的情况。
就是这样,我要去睡觉了,希望我说得通