JS事件冒泡是理解DOM操作的很好的例子,本文从事件、事件冒泡原理、冒泡处理三个角度来全面介绍JS的冒泡事件,你会发并没有那么神秘,跟那个冒泡排序也没有任何关系。

JS中的事件
要理解事件冒泡机制,就得先了解事件。
浏览器是事件驱动型的,根据用户的行为触发不同的事件,根据事件执行相应的操作。我们较为熟悉的事件有三大类型:鼠标键盘事件、页面事件、表单相关事件。
鼠标键盘事件:onclick、ondbclick、onmousedown、onmouseup、onmouseover、onmousemove、onmouseout、onkeypress、onkeydown、onkeyup;
页面事件:onload、onunload、onresize、onerror、onabort;
表单相关事件:onblur、onchange、onfocus、onreset、onsubmit。
需要注意的是事件处理程序中的变量event保留着事件对象的信息,包括比如click事件,事件属性里有点击位置相对于浏览器,以及页面的坐标信息,事件的类型(click),触发事件的DOM节点信息等。

什么是事件冒泡?
DOM中,树状结构决定了子元素肯定在父元素里,所以点击子元素,就同时点击了子元素和父元素,以及父元素的父元素,以此类推,当然最终的根节点都是文档,以及window。
试想,当一个子元素被点击的时候,不仅仅这个元素本身被点击了,因为这个元素也在其上一级父元素中(属于父级元素的地盘),所以相当于其父元素也被点击了,以此类推,一层一层往外推,最终整个文档也是被点击了,如果每个层级的节点元素都绑定了click事件,那么每个节点的click事件函数都会被执行。举个形象的例子,一个村里的人被打了(click),首先就要按照村里的规矩处理,同时这个村属于某个乡镇,当然也是相当于这个乡镇的人被打了,那么也要按照这个乡镇的规矩处理,以此一层一层往上报。这个例子不准确的地方就是,现实中一个人因为一个事件只会被处理一次,不会因为同一件事情多次处理。
以上这个事件从触发节点开始,逐层向上级元素传递的过程,就被形象地称为事件冒泡。以下例子很清晰展示了这个过程。

HTML代码

点击页面中 Child Span一次

控制台输出结果
从控制台的输出结果可以看到,虽然是Child Span被点击,而且是点击了一次,但是所有上层的父级元素的click事件都被触发,并且执行操作。

冒泡带来的烦恼
当上层(以及上上层,直至body元素)父级有子元素同样的方法,但你子元素的事件后,所有父级元素的同名函数也会从下到上,由里往外,挨个执行,但是大多数情况下,我们只希望子当事元素事件执行,不希望层层执行,这就要想办法阻止这种冒泡的情况发生。比如我们点击Child Span的时候只显示 Child Span的内容。结合刚刚的例子就是,村里发生了打人事件,在村里解决了,就没必要一层一层往上报,在层层处理了。
如何处理事件冒泡?
有三种思路可以处理事件冒泡带来的弊端:
1 阻止事件继续往上层传递的过程
利用事件的stopPropagation()函数终止往父级元素冒泡的过程。

再次点击span元素,其父元素没有因为span元素被点击而执行了。

注意 该方法具有兼容性的问题,Event.stopPropagation()在支持W3C的浏览器中使用没有问题,但是在IE浏览器就失效了,在IE中使用 Event.cancelBubble=true来代替:
if (Event.stopPropagation){
Event.stopPropagation(); }else{
Event.cancelBubble=true;
}
2 不阻止冒泡过程,修改执行的函数方法
这种方法是不阻止事件的冒泡过程,但是利用触发事件自带的信息,在各个元素节点的执行函数中添加判断,如果是当前节点触发的就执行,如果不是当前节点就不作任何操作。

这两种方法虽然在阻止事件冒泡方法不同,但实现起来都必须要在参与冒泡的过程所有节点元素挨个添加阻止函数或者判断函数,当节点表多的时候,这个操作起来就很会增加工作量,并造成大量重复代码,效率较低。
3 不阻止冒泡过程,在冒泡到根节点进行判断
这种方法同样不阻止事件的冒泡过程,同时也不在冒泡过程的各元素执行方法上添加判断,而是在冒泡过程中的某个父节点,对其所有下属的节点事件进行判断,然后执行相应的操作。
注意这个冒泡过程的最终节点,不一定要到body,到文档,到window,可以是冒泡过程中的任一一个终止冒泡的节点,所以我们可以在这个节点上,对其所有子元素的冒泡事件进行判断和处理。
比如我们选择DIV1作为统一处理节点,那么DIV1下的所有元素冒泡事件都在这里处理,而所有子元素都不做任何操作:

当然,这里为了说明问题,选择了DIV1,其实一般是在body节点进行。
其实这种元素本身触发事件,但是事件执行的方法不在元素本身,而是在其父元素的某个节点上,这种“偷懒”的模式,叫做事件委托。
以上就是事件冒泡的全部知识,如有错误欢迎指正,如有更好的讲解,也请留言交流。