先经历从上到下的捕获阶段,再经历从下到上的冒泡阶段。
addEventListener(‘eventName’, fn , false/true )
第三个参数可以选择阶段,默认是false ( 冒泡 内→外 ) true 是 捕获 外→内
可以使用event.stopPropagation()来阻止捕获或冒泡。
DOM 的事件操作(监听和触发),都定义在EventTarget接口。所有节点对象都部署了这个接口
该接口主要提供三个实例方法:
addEventListener:绑定事件的监听函数
removeEventListener:移除事件的监听函数
dispatchEvent:触发事件
<div class="grandfather">
<div class="father">
<div class="son">
<button>事件按钮</button>
</div>
</div>
</div>
给三个div分别添加事件的监听fnYe/fnBa/fnEr
点击事件按钮, grandfather , father , son算不算都被点击了?
答案是算的。
历史小知识:
当年IE认为应该从内而外(冒泡)
而网景认为要从内而外(捕获)
两家公司争论不休,苦了开发者们
后来W3C出了标准,要求先捕获再冒泡
IE5*:baba.attachEvent(‘onclick’,fn)//冒泡
网景:baba.addEventListener(‘click’,fn)//捕获
W3C:baba.addEventListener(‘click’,fn,bool)
事件参考:https://developer.mozilla.org/zh-CN/docs/Web/Events
EventTarget.addEventListener()(‘click’,fn,bool)
如果bool不传或指定为falsy
就让fn走冒泡,即当浏览器在冒泡阶段发现baba有fn监听函数,就会调用fn,并提供事件信息。
如果bool指定为true
就让fn走捕获,即当浏览器在捕获阶段发现baba有fn监听函数,就会调用fn,并且提供事件信息
e.target - 用户操作的元素
e.currentTarget-程序员监听的元素
this是e.currentTarget,我个人不推荐使用它
比如:
div>span{文字},用户点击文字
e.target就是span
e.currentTarget就是div
e.stopPropagation():取消冒泡
e.stopPropagation()可打断冒泡,浏览器不再向上走
一般用于封装某些独立组件
注意:捕获不可以取消但是冒泡可以
有些事件不可以取消冒泡
比如scroll:
Bubbles:冒泡
Cancelable:能否取消冒泡
概念: 事件委托也叫事件代理,“事件代理”即是把原本需要绑定在子元素的响应事件(click、keydown…)委托给父元素,让父元素担当事件监听的职务。事件代理的原理是DOM元素的事件冒泡。
假设现在要给100个按钮上监听:点击不同的按钮时打印出按钮的编号
代码:
//html
div>button{按钮 $}*100
//js
div1.addEventListener('click',(e)=>{
const t = e.target
if(t.tagName.toLowerCase() === 'button'){
console.log('button 被点击了')
console.log('button的编号是'+ t.textContent)
}
})
我们可以通过监听所有button元素的父元素div1,当target为button时,打印出编号
事件委托的优点:
1.可以大量节省内存占用,减少事件注册。
2.可以实现当新增子对象时无需再次对其绑定(动态绑定事件)