【前置知识】

  • 事件捕获
  • 事件冒泡

什么是事件委托

捕获和冒泡允许我们实现一种被称为 事件委托 的强大的事件处理模式。

思路

如果我们有许多以类似方式处理的元素,那么就不必为每个元素分配一个处理程序 —— 而是将单个处理程序放在它们的共同祖先上。

如图

image.png

该表格有9个格子,想要实现点击时高亮显示被点击的单元格 。

代码大概如下

  1. <table>
  2. <tr>
  3. <td class="a1">1</td>
  4. <td class="a2">2</td>
  5. <td class="a3">3</td>
  6. </tr>
  7. <tr>
  8. <td class="a4">4</td>
  9. <td class="a5">5</td>
  10. <td class="a6">6</td>
  11. </tr>
  12. <tr>
  13. <td class="a7">7</td>
  14. <td class="a8">8</td>
  15. <td class="a9">9</td>
  16. </tr>
  17. </table>

效率低下的做法: 为每个 <td> (可能更多)分配一个 onclick
~~
事件委托做法:直接在 <table> 设置一个“捕获所有”的处理程序。

  1. let selectedTd;
  2. let table = document.getElementsByTagName('table');
  3. let highlight = (td) => {
  4. if(selectedTd) {// 移除现有的高亮显示,如果有的话
  5. selectedTd.classList.remove('highlight')
  6. }
  7. selectedTd = td;
  8. selectedTd.classList.add('highlight');
  9. }
  10. table.onclick = (event) => {
  11. let target = event.target; //在哪里点击?
  12. if(target.tagName != 'TD') return;
  13. highlight(target)
  14. }

什么是事件委托

  • 事件委托指的是不在事件的发生地(直接DOM)上设置监听函数,而是在其父元素上设置监听函数。
  • 通过事件冒泡,父元素可以监听到被触发的子元素事件,通过判断事件发生元素DOM的类型,来作出不同的响应。
  • 当子元素有很多时,使用事件委托可以避免对特定的每个节点添加事件监听器,事件监听被添加到它们的父元素上,事件监听函数这是可以从子元素上冒泡上来的事件,找到是哪个子元素事件。

怎么阻止默认动作

默认动作指的是什么?

默认动作指的是浏览器自己的行为。

例如:

  • 点击 <a href="#"> 的时候浏览器自动跳转到指定页面。
  • 滚动鼠标时页面会向下滚动,但我们按空格键和按方向键时页面也会向下滚动。
  • 等等

有时候有一些需求,为了更好的用户体验,需要阻止浏览器本身的默认行动。

办法

有两种方式:

  • 主流的方法是使用 event 对象,有一个 event.preventDefault() 方法。
  • 如果处理程序是使用 on<event>(而不是 addEventListener)分配的,那返回 false 也同样有效。


  1. <a href="/" onclick="return false">Click here</a>
  2. //or
  3. <a href="/" onclick="event.preventDefault()">Click here</a>

怎么阻止事件冒泡

例子:

  1. <div class="爷爷">
  2. <div class="爸爸">
  3. <div class="儿子">
  4. 文字
  5. </div>
  6. </div>
  7. </div>

如上代码,假如我分别给爷爷、爸爸、儿子绑定 fnYefnBafnEr 三种点击事件。

  • 如果我没有阻止默认事件,则默认会按下面执行:
  • 当我点击 文字 时,就会按照事件捕获从 Window —> Document —> <html> —> <body> —> <div class="爷爷"> —><div class="爸爸"> —><div class="儿子"> 寻找是否有监听。
  • 然后,就会按照冒泡事件从<div class="儿子"> 一直到 Window 的过程寻找是否有监听,并依次执行监听,事件捕获是相反的。

DOM事件相关 - 图2

:::info 趣事:
IE5支持事件冒泡,而网景支持事件捕获。因为意见不合这两家公司闹到w3c。然后为了让这两家公司觉得公平,就规定浏览器应该同时支持两种调用顺序。 :::

如何阻止事件冒泡?

冒泡事件如同冒泡一样,从底部上升到水面,这个上升的过程还会依次执行代码,例如上面的儿子爸爸爷爷的代码,如图
image.png
默认情况下,当我点击 儿子 时,就会依次执行fuerfubafuye ,
如果我只想执行 fuer ,不想执行 后面的fubafuye ,就需要阻止冒泡事件。

两种方法:

  1. event.stopPropagation(); //W3C
  2. //or
  3. event.cancelBubble = true; //IE

虽然不太可能遇到,但如果需要兼容IE,可以这样:

  1. if (document.all) {
  2. // IE
  3. event.cancelBubble = true;
  4. } else {
  5. event.stopPropagation();
  6. }


【资料来源】 事件委托—-javascript.info 冒泡和捕获—-JavaScript.info 浏览器默认行为—-JavaScript.info