今天我们来说一下前端开发者必须知道的JavaScript事件模型。


DOM事件流

DOM(文档对象模型)结构是一个树型结构,当一个HTML元素产生一个事件时,该事件会在元素结点与根节点之间按特定的顺序传播,路径所经过的节点都会收到该事件,这个传播过程可称为DOM事件流。


事件顺序有两种类型:事件捕捉和事件冒泡


冒泡型事件(Event Bubbling)


这是IE浏览器对事件模型的实现,也是最容易理解的,至少笔者觉得比较符合实际的。冒泡,顾名思义,事件像个水中的气泡一样一直往上冒,直到顶端。从DOM树型结构上理解,就是事件由叶子节点沿祖先结点一直向上传递直到根节点;从浏览器界面视图HTML元素排列层次上理解就是事件由具有从属关系的最确定的目标元素一直传递到最不确定的目标元素.冒泡技术.冒泡型事件的基本思想,事件按照从特定的事件目标开始到最不确定的事件目标.


捕获型事件(Event Capturing)


Netscape 的实现,它与冒泡型刚好相反,由DOM树最顶层元素一直到最精确的元素,这个事件模型对于开发者来说(至少是我..)有点费解,因为直观上的理解应该如同冒泡型,事件传递应该由最确定的元素,即事件产生元素开始。


wKiom1Me07ewfARLAABpjJZlJWo319.jpg

DOM标准的事件模型


我们已经对上面两个不同的事件模型进行了解释和对比。DOM标准同时支持两种事件模型,即捕获型事件与冒泡型事件,但是,捕获型事件先发生。两种事件流都会触发DOM中的所有对象,从document对象开始,也在document对象结束(大部分兼容标准的浏览器会继续将事件是捕捉/冒泡延续到window对象)。


wKioL1Me05yiV5VDAAA8FZAlT-E784.jpg

如图:首先是捕获式传递事件,接着是冒泡式传递,所以,如果一个处理函数既注册了捕获型事件的监听,又注册冒泡型事件监听,那么在DOM事件模型中它就会被调用两次


DOM标准的事件模型最独特的性质是,文本节点也会触发事件(而在IE不会)。


wKiom1Me1FnR034RAADGL4AXLFQ065.jpg

事件传送


如果为一个超链接添加了click事件监听器,那么当该链接被点击时该事件监听器就会被执行。但如果把该事件监听器指派给了包含该链接的p元素或者位于DOM树顶端的document节点,那么点击该链接也同样会触发该事件监听器。这是因为事件不仅仅对触发的目标元素产生影响,它们还会对沿着DOM结构的所有元素产生影响。这就是大家所熟悉的事件转送。


W3C事件模型中明确地指出了事件转送的原理。事件传送可以分为3个阶段


(1)在事件捕捉(Capturing)阶段,事件将沿着DOM树向下转送,目标节点的每一个祖先节点,直至目标节点。例如,若用户单击了一个超链接,则该单击事件将从document节点转送到html元素,body元素以及包含该链接的p元素。


在此过程中,浏览器都会检测针对该事件的捕捉事件监听器,并且运行这件事件监听器。


(2) 在目标(target)阶段,浏览器在查找到已经指定给目标事件的事件监听器之后,就会运行 该事件监听器。目标节点就是触发事件的DOM节点。例如,如果用户单击一个超链接,那么该链接就是目标节点(此时的目标节点实际上是超链接内的文本节点)。


(3)在冒泡(Bubbling)阶段,事件将沿着DOM树向上转送,再次逐个访问目标元素的祖先节点到document节点。该过程中的每一步。浏览器都将检测那些不是捕捉事件监听器的事件监听器,并执行它们。


所有的事件都要经过捕捉阶段和目标阶段,但是有些事件会跳过冒泡阶段。例如,让元素获得输入焦点的focus事件以及失去输入焦点的blur事件就都不会冒泡。


理论说的差不多了,现在我们来结合代码看一下:


<div id="one">
    <div id="two">
        <button>click</button>
    </div>
</div>
<p>
    Message:
</p>


脚本代码:


$("#one").click(one);
$("#two").click(two);
$("button").click(three);


运行结果:

wKiom1Me2LjS0gwsAACBTlgHNZE965.jpg

能看到事件是从里到外冒泡型的触发的(jquery默认是冒泡型事件)!


W3C标准中则是用Element.addEventListener(EventType,someFunction,useCapture)方法来决定时间类型,第一个参数是元素类型,第二个参数是事件监听器函数,第三个参数则是决定在哪个阶段执行监听器函数,true为捕捉(Capture)阶段, false则为冒泡(Bubble)阶段。