DOM 的事件操作(监听和触发),都定义在EventTarget接口。 接口主要提供三个实例方法。
- addEventListener:绑定事件的监听函数
- removeEventListener:移除事件的监听函数
- dispatchEvent:触发事件
一个事件发生后,会在子元素及父元素之间进行传播(propagation),这种传播分为三个阶段。(这种三阶段的传播模型,使得同一个事件会在多个节点上触发。)
- 由外向内找监听函数就是事件捕获
- 在目标节点触发事件
- 由内而外找监听函数就是事件冒泡
事件传播的最上层对象是window,上例的事件传播顺序,在捕获阶段依次为window、document、html、body、父节点、目标节点,在冒泡阶段依次为目标节点、父节点、body、html、document、window。
DOM事件传播的三个阶段:捕获阶段,目标阶段,冒泡阶段
此处以点击事件为例
<div class=爷爷>
<div class=爸爸>
<div class=儿子>
文字
</div>
</div>
</div>
即 .爷爷>.爸爸>.儿子 给三个div分别添加事件监听 fnYe / fnBa / fnEr ,点击‘文字’后,调用顺序是怎样的?
IE 5*:baba.attachEvent('onclick', fn) // 冒泡
网景:baba.addEventListener('click',fn) // 捕获
W3C:baba.addEventListener('click', fn, bool) // bool===空/falsy,冒泡 ; bool===true,捕获
W3C制定了标准
首先 按爷爷=>爸爸=>儿子顺序看有没有函数监听
然后 按儿子=>爸爸=>爷爷顺序看有没有函数监听
有监听函数就调用,并提供事件信息,没有就跳过
从外向内找监听函数,叫事件捕获
从内向外找监听函数,叫事件冒泡
开发者自己选择把 fnYe 放在捕获阶段还是放在冒泡阶段
代码示例
W3C 事件模型
先捕获(先爸爸=>儿子)再冒泡(再儿子=>爸爸)
注意 e 对象被传给所有监听函数
事件结束后,e 对象就不存在了
注意
div > span{文字},用户点击文字
e.target 就是 span , e.target就是被用户操作的元素
e.currentTarget (this) 就是 div , e.currentTarget就是被监听的元素
捕获不可取消,但冒泡可以
e.stopPropagation() 可中断冒泡,浏览器不再向上走
特例
只有一个 div 被监听(不考虑父子同时被监听),fn 分别在捕获阶段和冒泡阶段监听 , click 事件
用户点击的元素就是开发者监听的
div.addEventLisenter('click', f1)
div.addEventLisenter('click', f2, true)
先执行f1还是f2 ?
答案:谁先监听谁先执行。因为他们是同辈。