浏览器的事件机制

事件机制

事件机制也叫做‘冒泡&捕获’,也可以叫做事件流。

三大共识

假设有个id等于parent的div,它里面有个id等于child的div,当用户点击了child子元素时:

  • 操作系统是最先知道用户点击了鼠标,浏览器次之。

  • 子元素(child)被点击了,也就意味着父元素(parent)也被点击了。

  • 如果同时监听child和parent,那谁先通知呢?这就涉及到两个阶段。

    捕获阶段

    parent先通知,child后通知。

在早期Navigator浏览器是默认支持捕获阶段的。当点击child子元素时,window对象首先接受到click事件然后事件沿DOM树依次向下,一直传播到事件的实际目标。
HTML代码

1
2
3
4
5
<div id=xparent><div id=xchild></div></div>
<style>
#xparent{background: green;padding: 10px}
#xchild{width: 100px;height: 100px;background: red}
</style>

JS代码

1
2
3
4
//由于Navigator浏览器支持的是'DOM1级事件’,用addElementListener来模拟这个阶段。
//因为parent是全局变量,不能进行赋值。
xparent.addEventListener('click',function(){console.log('parent')},true)
xchild.addEventListener('click',function(){console.log('child')},true)

此时,控制台会先打出’parent’,后打出’child’。

冒泡阶段

child先通知,parent后通知。

在IE早期,IE是默认冒泡机制,事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级传播到较为不具体的节点(文档)。
用户点击child子元素时,click事件首先在<div id=child>元素上发生,而这个元素就是我们单击的元素,然后click事件依次沿DOM树向上传播,一直到window对象。
JS代码

1
2
3
4
5
// onclick点击是默认冒泡的。
xparent.onclick = function(){console.log('parent')}
xchild.onclick=function(){console.log('child')}
//'parent'
'child'

W3C事件模型

W3C将DOM事件升级到‘DOM2级事件’后,为了区别浏览器如何通知捕获和冒泡这两个阶段,制定了以下标准:

1
2
3
button.addEventListener('click',fn,true)  //捕获
button.addEventListener('click',fn) //冒泡
//第三个参数默认是false,一般省略不写。

如何阻止冒泡

JS代码

1
2
xchild.addEventListener('click',function(e){console.log('child'),e.stopPropagation()})
xparent.addEventListener('click',function(e){console.log('parent')})

此时,控制台只会打印’child’。
e.stopPropagation()也是可以阻止捕获的。(propagation指传播)

总结

冒泡和捕获永远不要混着使用,个人建议使用冒泡。