事件传播分为三步
- 捕获 CAPTURING_PHASE 1
- 目标 AT_TARGET 2
- 冒泡 BUBBLING_PHASE 3
当我们触发当前元素的某个事件行为的时候
- 1.首先会从最外层window开始,一层层的按照结构向里层查找【捕获:为冒泡阶段提供传播的路径 => ev.path】
- 2.找到当前的事件源,触发当前事件源的相关行为 【目标】
- 3.不仅当前事件源的相关行为被触发,其所有祖先元素的相关事件行为都会被触发(在这个过程中,哪一个元素的事件行为绑定了方法,方法都会被触发执行,而且顺序是由里层向外层传播) 【冒泡】
在Event.prototype上有几个对这个过程进行操作的方法:
- 阻止事件的默认行为(比如浏览器F5刷新)
- ev.preventDefault() / ev.returnValue=false
- 阻止事件的冒泡传播
- ev.stopPropagation() / ev.cancelBubble=true
事件委托/事件代理
- 利用事件的冒泡传播机制,我们把当前元素事件触发要做的事情,全部委托给外层容器,这样触发当前元素的某个事件行为,其外层容器(祖先元素)的相关事件行为也会被触发,再给外层容器事件触发绑定的方法中,基于事件源不同,处理要做的不同的事情
- 优点:
- 性能很好(比一般的事件绑定性能提高40%以上,尤其需要单独绑定的元素越多,性能越好)=>项目中遇到,一个容器中很多元素的某个行为触发要做一些事情,此时杜绝一个个的绑定,直接基于事件委托处理(Vue项目中也一样)
- 灵活,基于阻止冒泡传播,可以灵活控制哪些走事件代理,哪些不需要走
- 某些需求必须基于事件委托来实现:例如点击A/B做什么,剩下不管点击谁都统一做什么
document.body.onclick = function (ev) {
let target = ev.target,
id = target.id;
if (id === "outer") {
console.log('OUTER');
return;
}
if (id === "inner") {
console.log('INNER');
return;
}
console.log('啥也不是');
};
center.onclick = function (ev) {
console.log('CENTER');
ev.stopPropagation();
};