红宝书第二十三讲:详解DOM事件模型:冒泡与事件委托

资料取自《JavaScript高级程序设计(第5版)》
查看总目录:红宝书学习大纲


一、事件冒泡:从“子”到“父”的传递过程

当点击一个元素时,事件会从最深层元素逐级向上传递到根节点,即 事件冒泡12
类比:石头扔进水里,波纹从中心扩散到外围。

flowchart TD
    点击按钮 --> 按钮元素(div#child)
    按钮元素 --> 父元素(div#parent)
    父元素 --> body
    body --> html
    html --> document
代码验证:点击子元素触发父元素监听
<div id="parent">
  父元素
  <button id="child">子按钮</button>
</div>

<script>
  document.getElementById('parent').addEventListener('click', () => {
    console.log('父元素被触发了!'); // 点击按钮时会打印
  });
</script>

二、事件对象的关键属性

事件处理函数的参数 event 包含关键属性:

  • target → 实际触发事件的元素(如点击的按钮)3
  • currentTarget → 当前正在处理事件的元素(如父元素)1
  • stopPropagation() → 阻止事件继续冒泡1
parent.addEventListener('click', (e) => {
  console.log('实际触发者:', e.target.id); // 输出 'child'
  console.log('当前处理者:', e.currentTarget.id); // 输出 'parent'
  e.stopPropagation(); // 阻止冒泡到更高层
});

三、事件委托:用“父级代理”子级的事件

场景:列表中有多个子项需要点击处理。
传统方式 → 为每个子项绑定事件(性能差)2
事件委托 → 利用冒泡,只在父级绑定一个事件2

示例:点击任意列表项时打印内容
<ul id="list">
  <li data-action="go">去学习</li>
  <li data-action="eat">去吃饭</li>
  <li data-action="sleep">去睡觉</li>
</ul>

<script>
  document.getElementById('list').addEventListener('click', (e) => {
    const action = e.target.dataset.action;
    if (action) {
      console.log('执行操作:', action); // 点击任意li触发
    }
  });
</script>

优点:动态新增子项无需重新绑定事件,节省内存2


四、event.preventDefault() VS event.stopPropagation()

  • preventDefault()阻止默认行为(如点击链接不跳转)1
  • stopPropagation()阻止冒泡(父元素不再触发)1
document.querySelector('a').addEventListener('click', (e) => {
  e.preventDefault(); // 阻止跳转
  e.stopPropagation(); // 防止父元素的事件被触发
});

目录:总目录
上篇文章:红宝书第二十二讲:详解JavaScript类型化数组与二进制数据处理

下篇文章:红宝书第二十四讲:详解BOM对象:window、location、history

脚注


  1. 《JavaScript高级程序设计(第5版)》中的事件对象属性表解释了bubblesstopPropagation()
  2. 《JavaScript高级程序设计(第5版)》通过父元素代理处理多个子项事件示例说明事件委托
  3. 《JavaScript高级程序设计(第5版)》代码显示通过event.target区分事件源

kovli
13 声望7 粉丝