当事件的目标是 Winow 对象,或其他独立对象(如 XMLHttpRequest)时,浏览器对于事件的回应就只是在这个对象上调用相应的处理器。当事件的目标是 Document 或 document Element,则情况更复杂一些。
当该目标元素上注册的事件处理器调用后,大多数事件会沿着 DOM 树冒泡。目标的父元素上的事件处理器会调用。然后就是父父元素,一直到 Document 对象,之后就是 Window 对象。事件冒泡为在大量单独文档元素上注册处理程序提供了替代方案,即在共同的祖先元素上注册一个处理程序来处理所有的事件。例如,可以在<form>元素上注册“change”事件处理程序来取代在表单的每个元素上注册“change”事件处理程序。
发生在文档元素上的大多数事件都会冒泡,值得注意的是 focus、blur、scroll 是例外。文档元素上的 load 事件会冒泡,但只冒泡到 Document 对象,不会传播到 Window 对象。只有当整个文档加载完毕才会触发 Window 对象的 load 事件。
事件冒泡是事件传播的第三阶段。目标对象自身调用事件处理器是第二阶段。第一阶段发生在调用目标对象上的事件处理程序之前,叫捕捉阶段。还记得 addEventListener()有一个boolean值作为它的第三个参数,当值为 true 时,该事件处理器是被注册为一个捕捉事件处理器,用于在事件传播的第一阶段调用。事件传播被广泛支持:包括IE在内的所有浏览器都行,并且是所有的处理器都行,不管它们是如何注册的(除非它们是被注册为捕捉事件处理器)。事件捕捉,相反,只对那些用 addEventListener()注册的且第三个参数是true的管用。就这意味着,IE 9 之前的版本不支持事件捕捉,并且,在写这本书的时候,事件捕捉也不是一个常用的技术。
事件传播的捕获阶段像倒过来的冒泡阶段。Window 对象上的捕捉处理器会最先调用,之后是 Document 对象上的捕捉处理器,之后是 body 对象,等等,沿着 DOM 树一直到事件目标的父元素上的捕捉事件处理器被调用。注册在事件目标自身上的捕捉事件处理器不会调用。
事件捕获提供了在事件没有送达目标之前查看它们的机会。事件捕获可以被用于程序调试,或用于事件取消技术,过滤掉事件从而使目标事件处理程序不会被调用。常用的一个情况就是处理鼠标拖放,鼠标动作事件需要被被拖放的对象来处理,not the document elements over which it is dragged。