Javascript中的事件冒泡与捕获
事件冒泡和事件捕获
起因:今天在封装一个bind
函数的时候,发现el.addEventListener
函数支持第三个参数,useCapture
:是否使用事件捕获,觉得有点模糊
-
Js事件流
页面的哪一部分会拥有某个特定事件,例子:在纸上画一组同心圆,如果手指放在同心圆上,那么手指向的不是一个圆,而是纸上所有的圆。在页面中也是,如果点击了某个按钮,同时也单击了按钮的容器元素,甚至也单击了整个页面
事件流:页面接收事件的顺序,IE和Netscape最开始提出了两种概念,两种事件冒泡流,事件捕获流
<!-- 假如有这样一段相同的html -->
<!DOCTYPE html>
<html>
<head><title>bubbling and capture</title></head>
<body>
<div id="myDiv">Click me</div>
</body>
</html>
-
事件冒泡(event bubbling)
IE
提出的事件处理方式,即事件开始时,由最具体的元素接收,然后逐级向上传播到不具体的节点如果点击例子中的
div
元素,那么这个click的事件传播顺序如下:div -> body -> html -> document
也就是说,
click
事件首先会在div
元素上触发,这个元素就是我们单击的元素,然后click
事件会沿着DOM
树向上传播,在每一级节点都会发生,直到传播到document对象所有浏览器都支持事件冒泡,但是在具体实现上会有些许的差别,例如IE5.5以及更早版本中的事件冒泡会跳过
Html
元素,直接从body
跳到document
元素,而IE9,Firefox,Chrome,Safari则将事件一直冒泡到window对象 -
事件捕获(event capturing)
Netscape
网井团队则题除另一种事件流叫做事件捕获,事件捕获的思想是不太具体的节点应该更早的接收到事件,而具体的节点应该最后接收到事件,事件捕获的用意在于事件达到预计目标之前捕获他,如果还是以上面的例子,单击div
那么触发顺序会是这样
document -> html -> body -> div
在事件捕获过程中,
document
对象首先接收到click
事件,然后事件沿DOM
树依次向下,一直传播到时间的实际目标即div
元素虽然
Netscape
是开发这种事件流,但是目前所有较新的浏览器都支持这种事件流模型,尽管“DOM2级事件”规范要求事件应该从document
对象开始传播,但是这些浏览器都是从window
对象开始捕获事件由于老版本浏览器不支持,所以很少使用事件捕获,推荐放心使用事件冒泡,在有特殊需求时再使用事件捕获
-
DOM事件流
"DOM2级别事件"什么是DOM2级别规定的事件流包括三个阶段
|事件捕获阶段|处于目标阶段|事件冒泡阶段|
|----|----|----|----|
|事件未处于目标,事件传递按照从大到小,从外层顺着DOM
树向目标传递,触发顺序,从外到里|处于目标阶段:事件会在目标元素上发生,并且在事件处理中堪称冒泡阶段的一部分|事件冒泡阶段:事件从目标元素开始,顺着DOM
树往外传递,依次到父容器,body
,html
,document
部分浏览器会到window
-
什么是DOM2级别?什么是DOM0级别?什么是DOM事件处理程序等级
事件:用户或浏览器自身执行的某种动作,例如
click,load,mouseover
都是事件名字,而相应某个事件的函数,就叫做事件处理程序,事件处理程序的名字以on
开头,例如click
事件的处理程序就是onclick
,load
事件的处理陈鼓型就是onload
-
HTML事件处理程序
某个
html
元素支持某种事件,都可以使用一个与对应时间处理程序同名的html
属性来指定,这个属性的值则是能够执行的javascript
代码,例如<div onclick="alert(1)"></div>
该事件触发于:冒泡阶段触发
-
DOM0级事件处理程序
html事件处理程序
的javascript
逻辑和html
耦合太强DOM0级事件处理程序写法
var btn = document.getElementById('myBtn') btn.onclick= function(){ alert(this.id) }
此处的
this
指向的是这个触发元素,并且可以通过this
对象访问元素的任何属性和方法,以这种方式添加的事件处理程序会在事件流的冒泡阶段被处理移除事件监听 :
btn.onclick = null
-
DOM2级事件处理程序
两个方法:
addEventListener
和removeEventListener
所有的
DOM
节点都包含这两个方法,并且接受三个参数,要处理的事件名,作为事件处理函数的函数和一个布尔值,最后这个布尔值如果是true
,表示在捕获阶段调用事件处理程序,如果是false
则表示在冒泡阶段调用事件处理程序而事件流的顺序是捕获-目标-冒泡,捕获阶段会在冒泡事件处理之前,所以改为
true
的话有可能会影响正常的时间顺序demo如下:
var btn = document.getElementById('myBtn') btn.addEventListener('click',function(){ alert(this.id) },false)
DOM2级方法添加事件处理程序的好处是可以添加多个事件处理程序,而前两个则是会替换掉事件处理程序,因为属性只有一个,而元素的方法也会重写
但是也意味着,不能通过重写来移除事件处理程序,所以通过
removeEventListener
来移除事件处理程序,并且匿名函数无法移除大多数情况下,都是将事件处理程序添加到事件流的冒泡阶段,这样可以最大限度的兼容各种浏览器,最好只在需要在事件到达目标之前截获它的时候将事件处理程序添加到捕获阶段,如果不是特别需要,不建议在时间捕获阶段注册事件处理程序
-
IE事件处理程序
IE中实现了与
DOM
中类似的两个方法attachEvent
和detachEvent
,但是仅接受两个参数,一个是事件处理程序名称与事件处理函数,由于IE8
以及更早的版本只支持事件冒泡,所以通过attachEvent
添加的事件处理程序都会被添加到事件冒泡阶段需要注意的是:
1.
attachEvent
和DOM级方法主要区别在事件处理程序的作用域,DOM0级会在所属元素的作用域内,而attachEvent
事件处理程序会在全局作用域中运行,因此在attachEvent添加的函数中,this指向window2.
attachEvent
添加多个事件时候时,不是按照添加顺序执行,而是按照相反的顺序执行,后添加,先执行
-
总结
el.addEventListener
函数的第三个参数问题得到了解决,使用这种方法表示绑定DOM2
级别的事件监听程序,可以重复指定,第三个参数表示是否在捕获阶段处理事件,捕获-》 目标 -》 冒泡- 第三个参数默认
false
,如没有特殊情况不推荐使用在捕获阶段处理时间程序 - 了解了
事件流
,捕获和冒泡
,DOM事件类型级别(HTML级事件处理程序,DOM0级事件处理程序,DOM2级事件处理程序,IE事件处理程序)
- 事件流过程,先从外到内,捕获阶段,到达目标阶段,从内到外冒泡