dom事件模型

74 阅读3分钟

一、核心概念:DOM事件流(事件传播机制)

DOM事件模型描述了事件在DOM树中传播的完整流程,分为三个阶段,遵循“先捕获后冒泡”的顺序:

  1. 事件捕获阶段(Capture Phase)

    • 事件从最顶层的Window对象开始,逐级向下传播到目标元素的父元素(不包含目标元素本身)。
    • 作用:提前拦截事件(如阻止某些操作)。
  2. 目标阶段(Target Phase)

    • 事件到达触发事件的目标元素(如点击的按钮),执行该元素上的事件处理函数。
  3. 事件冒泡阶段(Bubbling Phase)

    • 事件从目标元素开始,逐级向上传播到最顶层的Window对象
    • 作用:实现事件委托(通过父元素处理子元素事件)。

二、关键机制:捕获与冒泡的触发与控制

1. 如何触发捕获/冒泡阶段的事件?

通过addEventListener的第三个参数控制(useCapture,默认为false):

const parent = document.getElementById('parent');
const child = document.getElementById('child');

// 冒泡阶段触发(默认):事件冒泡到parent时执行
parent.addEventListener('click', () => console.log('parent冒泡'), false);

// 捕获阶段触发:事件捕获到parent时执行
parent.addEventListener('click', () => console.log('parent捕获'), true);

// 点击child时,执行顺序:
// 1. parent捕获(捕获阶段)
// 2. child点击(目标阶段)
// 3. parent冒泡(冒泡阶段)

2. 如何阻止事件传播?

  • event.stopPropagation():阻止事件继续传播(无论当前在捕获还是冒泡阶段)。

    child.addEventListener('click', (e) => {
      e.stopPropagation(); // 阻止事件传播到父元素
      console.log('child被点击');
    });
    
  • event.stopImmediatePropagation():不仅阻止传播,还会阻止当前元素上后续的同类型事件处理函数。

    child.addEventListener('click', (e) => {
      e.stopImmediatePropagation();
      console.log('第一个处理函数');
    });
    child.addEventListener('click', () => {
      console.log('第二个处理函数(不会执行)');
    });
    

三、核心应用:事件委托(Event Delegation)

1. 原理

利用事件冒泡机制,将子元素的事件处理函数绑定到父元素上,通过event.target判断具体触发事件的子元素。

2. 代码示例(动态列表的点击事件)

<ul id="list">
  <li>项目1</li>
  <li>项目2</li>
  <!-- 动态添加的li也能触发事件 -->
</ul>

<script>
  const list = document.getElementById('list');
  
  // 事件委托:绑定到父元素ul
  list.addEventListener('click', (e) => {
    // 判断触发事件的是li元素
    if (e.target.tagName === 'LI') {
      console.log('点击了:', e.target.textContent);
    }
  });
  
  // 动态添加子元素(无需重新绑定事件)
  const newLi = document.createElement('li');
  newLi.textContent = '项目3';
  list.appendChild(newLi);
</script>

3. 优势

  • 减少事件绑定次数(尤其对大量子元素,如列表),优化性能;
  • 支持动态添加的元素(无需重新绑定事件)。

四、问题

  1. 问:事件捕获和冒泡的执行顺序是什么?

    • :先捕获(从Window到目标父元素)→ 目标阶段(目标元素)→ 再冒泡(从目标元素到Window)。
  2. 问:事件委托的核心原理是什么?适用于什么场景?

    • :核心是利用事件冒泡,将子元素事件绑定到父元素,通过event.target定位触发元素。适用于动态生成的元素(如列表项、表格行),或大量子元素的场景(减少内存占用)。
  3. 问:如何阻止默认事件(如表单提交、链接跳转)?

    • :使用event.preventDefault(),例如:
      // 阻止链接跳转
      document.querySelector('a').addEventListener('click', (e) => {
        e.preventDefault(); // 不会跳转到href指定的地址
      });
      
  4. 问:onclickaddEventListener的区别是什么?

    • onclick只能绑定一个事件处理函数(后绑定的会覆盖前一个),且只能在冒泡阶段触发;addEventListener可绑定多个函数,支持捕获阶段触发,功能更灵活。

五、总结

“DOM事件模型的核心是‘捕获→目标→冒泡’的三阶段传播机制:

  • 捕获阶段从顶层到目标父元素,可用于提前拦截事件;
  • 冒泡阶段从目标到顶层,是事件委托的基础(通过父元素处理子元素事件);
  • 实际开发中,常用事件委托优化大量子元素的事件处理,用stopPropagation控制传播,用preventDefault阻止默认行为。

例如在电商商品列表中,通过事件委托给ul绑定点击事件,无需为每个li单独绑定,既节省内存,又支持动态添加商品项的交互。”