冒泡和捕获
事件流模型
事件冒泡和事件捕获是两种事件流模型,什么是事件流模型呢?先看下DOM事件的特点。
DOM是嵌套的结构,当用户点击了一个按钮,那么按钮的父元素也被点击了,也就是说,事件发生在从document顶层节点到点击目标节点这个路径上的所有元素上。
<html>
<body>
<div id="root">
<div class="container">
<button class="btn-submit"></button>
</div>
</div>
</body>
</html>
上面示例中,html、body、container、button都被点击了,即都会触发点击事件。
那么点击顺序呢?先点击按钮还是先点击父元素?
事件流模型就是主要规定事件的触发顺序的事件模型。
捕获和冒泡是不同浏览器内核提出的不同的事件模型。
微软提出的事件流叫事件冒泡,也就是说事件的传播为:从事件开始的具体元素,一级级往上传播到较为不具体的节点。上面案例中,按照事件冒泡模型,触发点击事件的顺序为button->container->body->html。如果这些元素上注册了事件,就按照这个顺序触发回调函数。
网景团队提出的另一种事件流叫做事件捕获。它的原理刚好和事件冒泡相反,它的用意在于在事件到达预定目标之前捕获它,而最具体的节点应该是最后才接收到事件的。
IE9、Firefox、Chrome和Safari目前也支持这种事件流模型,但是有些老版本的浏览器不支持,所以很少人使用事件捕获,而是用事件冒泡的多一点。
目前W3C标准事件流包含捕获、目标、冒泡3个阶段,大多数浏览器基本是按照这个标准实现的。
值得注意的是,多数支持DOM事件流的浏览器都实现了一种特定的行为;即使“DOM2级事件”规范明确要求捕获阶段不会涉及事件目标,但IE9、Safari、Chrome、Firefox和Opera9.5及更高版本都会在捕获阶段触发事件对象上的事件。结果,就是有两个机会在目标对象上操作事件。
事件绑定
在监听事件时候,分为DOM0和DOM2两种事件绑定方法
DOM0级事件绑定
curEle.onclick=function() {};
DOM2级事件绑定
标准浏览器:
// 第三个参数是useCapature,表示在捕获阶段,还是在冒泡阶段触发事件
curEle.addEventListener('click', function() {}, false)
第三个参数是useCapature,表示在捕获阶段,还是在冒泡阶段触发事件
IE6-8:curEle.attachEvent('onclick', function() {})
阻止事件绑定
curEle.addEventListener('click', function(e) {
console.log(e);
e.stopPropagation();
}, false);
事件代理
什么是事件代理
事件代理,简单地说,就是让外层元素代理内层元素的事件,外层元素绑定一个事件回调,回调中判断点击目标,并处理内层元素的事件逻辑。
为什么需要事件代理
内层元素过多时候,每个元素绑定一个事件会带来较大的开销。使用事件代理可以减少事件绑定带来的性能损耗。
示例
<ul id="item-list">
<li>item1</li>
<li>item2</li>
<li>item3</li>
<li>item4</li>
</ul>
// 代理
var items = document.getElementById('item-list');
//事件捕获实现事件代理
items.addEventListener('click', (e) => {console.log('捕获:click ', e.target.innerHTML)}, true);
//事件冒泡实现事件代理
items.addEventListener('click', (e) => {console.log('冒泡:click ', e.target.innerHTML)}, false);