冒泡和捕获

事件流模型

事件冒泡和事件捕获是两种事件流模型,什么是事件流模型呢?先看下DOM事件的特点。

DOM是嵌套的结构,当用户点击了一个按钮,那么按钮的父元素也被点击了,也就是说,事件发生在从document顶层节点到点击目标节点这个路径上的所有元素上。

  1. <html>
  2. <body>
  3. <div id="root">
  4. <div class="container">
  5. <button class="btn-submit"></button>
  6. </div>
  7. </div>
  8. </body>
  9. </html>

DOM事件、冒泡和捕获、事件代理 - 图1

上面示例中,html、body、container、button都被点击了,即都会触发点击事件。

那么点击顺序呢?先点击按钮还是先点击父元素?

事件流模型就是主要规定事件的触发顺序的事件模型。

捕获和冒泡是不同浏览器内核提出的不同的事件模型。

微软提出的事件流叫事件冒泡,也就是说事件的传播为:从事件开始的具体元素,一级级往上传播到较为不具体的节点。上面案例中,按照事件冒泡模型,触发点击事件的顺序为button->container->body->html。如果这些元素上注册了事件,就按照这个顺序触发回调函数。

网景团队提出的另一种事件流叫做事件捕获。它的原理刚好和事件冒泡相反,它的用意在于在事件到达预定目标之前捕获它,而最具体的节点应该是最后才接收到事件的。
IE9、Firefox、Chrome和Safari目前也支持这种事件流模型,但是有些老版本的浏览器不支持,所以很少人使用事件捕获,而是用事件冒泡的多一点。

目前W3C标准事件流包含捕获、目标、冒泡3个阶段,大多数浏览器基本是按照这个标准实现的。

值得注意的是,多数支持DOM事件流的浏览器都实现了一种特定的行为;即使“DOM2级事件”规范明确要求捕获阶段不会涉及事件目标,但IE9、Safari、Chrome、Firefox和Opera9.5及更高版本都会在捕获阶段触发事件对象上的事件。结果,就是有两个机会在目标对象上操作事件。

DOM事件、冒泡和捕获、事件代理 - 图2

事件绑定

在监听事件时候,分为DOM0和DOM2两种事件绑定方法

DOM0级事件绑定

  1. curEle.onclick=function() {};

DOM2级事件绑定

标准浏览器:

  1. // 第三个参数是useCapature,表示在捕获阶段,还是在冒泡阶段触发事件
  2. curEle.addEventListener('click', function() {}, false)

第三个参数是useCapature,表示在捕获阶段,还是在冒泡阶段触发事件

IE6-8:curEle.attachEvent('onclick', function() {})

阻止事件绑定

  1. curEle.addEventListener('click', function(e) {
  2. console.log(e);
  3. e.stopPropagation();
  4. }, false);

事件代理

什么是事件代理

事件代理,简单地说,就是让外层元素代理内层元素的事件,外层元素绑定一个事件回调,回调中判断点击目标,并处理内层元素的事件逻辑。

为什么需要事件代理

内层元素过多时候,每个元素绑定一个事件会带来较大的开销。使用事件代理可以减少事件绑定带来的性能损耗。

示例

  1. <ul id="item-list">
  2. <li>item1</li>
  3. <li>item2</li>
  4. <li>item3</li>
  5. <li>item4</li>
  6. </ul>
  1. // 代理
  2. var items = document.getElementById('item-list');
  3. //事件捕获实现事件代理
  4. items.addEventListener('click', (e) => {console.log('捕获:click ', e.target.innerHTML)}, true);
  5. //事件冒泡实现事件代理
  6. items.addEventListener('click', (e) => {console.log('冒泡:click ', e.target.innerHTML)}, false);

参考文章

事件捕获、事件冒泡以及事件代理 - 掘金

js核心系列(九) ——事件冒泡,事件捕获,事件代理知多少 - 掘金

DOM 2 级事件的认识_dom2-CSDN博客