事件流描述的是从页面中接受事件的顺序,主要是事件冒泡和事件捕获。

事件冒泡

事件冒泡(event bubbling),即事件开始时由最具体的元素接收,然后逐级向上传播到 window 对象。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
  </head>
  <body>
    <div id="myDiv">Click</div>
  </body>
</html>

当点击了 div 元素,事件传播 div -> body -> html -> Document -> window。

事件捕获

事件捕获(event capturing),是由事件从 window 对象开始接收事件,然后逐级向下传播到具体元素。

如上代码,点击掉了 div 元素,事件传播 window -> Document -> html -> body -> div。

DOM 事件流

三个阶段:事件捕获阶段,处于目标阶段和事件冒泡阶段。

新增事件和删除事件的操作:addEventListener(type, listener [, options])removeEventListener(type, listener [, options])

事件委托

事件委托就是利用事件的冒泡原理,把元素的响应事件代理到其父辈元素上,可以减少循环绑定。

<!-- 普通的html列表标签 -->
<ul id="list">
  <li>item 1</li>
  <li>item 2</li>
  <li>item 3</li>
</ul>
/* 普通的遍历元素注册事件监听 */
var items = document.getElementsByTagName('li');
for (var i = 0; i < items.length; i++) {
  items[i].addEventListener('click', function (e) {
    e.target.parentNode.removeChild(e.target);
  });
}
/* 事件委托 */
var list = document.getElementById('list');
list.addEventListener('click', function (e) {
  list.removeChild(e.target);
});

event 对象的属性和方法

属性/方法 类型 说明
target Element 事件的目标
currentTarget Element 其事件处理程序当前正在处理事件的那么元素,即触发事件的元素
preventDefault Function 取消事件的默认行为
stopPropagation Function 取消事件的进一步捕获或冒泡

target 与 currentTarget

<div class="container">
  <button>Click me</button>
</div>
const div = document.querySelector('.container');
div.addEventListener('click', (e) => {
  console.log('target', e.target);
  console.log('currentTarget', e.currentTarget);
});

当我们点击按钮的时候,我们可以看到不同的输出结果

target <button>Click me</button>
currentTarget <div class="container">...</div>
  • targt 是触发事件的根元素
  • currentTarget 是处理该事件的元素

不会触发冒泡的事件

  • scroll
  • blur
  • focus
  • mouseentter
  • mouseleave

其他

React 的事件体系就是基于事件委托建立的,其中有很大的部分都是处理不同事件之间的差异性的,对于这些不会冒泡的事件,React 也进行了处理。

React 的事件系统可以参考上一篇的《React事件系统》

参考链接