DOM 事件处理方式演进

DOM0、DOM2、DOM3 三种事件处理方式的区别与用法

问题

介绍 DOM0、DOM2、DOM3 事件处理方式的区别。

解答

DOM0 级事件

通过 HTML 属性或元素属性直接绑定事件处理函数。

<!-- 方式1:HTML 属性 -->
<button onclick="handleClick()">点击</button>

<script>
function handleClick() {
  console.log('clicked');
}
</script>
// 方式2:元素属性
const btn = document.getElementById('btn');

btn.onclick = function() {
  console.log('clicked');
};

// 同一事件只能绑定一个处理函数,后面的会覆盖前面的
btn.onclick = function() {
  console.log('new handler'); // 只有这个会执行
};

// 移除事件
btn.onclick = null;

DOM2 级事件

引入 addEventListenerremoveEventListener,支持事件捕获和冒泡。

const btn = document.getElementById('btn');

function handler1() {
  console.log('handler1');
}

function handler2() {
  console.log('handler2');
}

// 可以绑定多个处理函数,按顺序执行
btn.addEventListener('click', handler1, false);
btn.addEventListener('click', handler2, false);

// 第三个参数:false 表示冒泡阶段触发(默认),true 表示捕获阶段触发
btn.addEventListener('click', handler1, true); // 捕获阶段

// 移除事件(必须是同一个函数引用)
btn.removeEventListener('click', handler1, false);
// 事件流演示:捕获 -> 目标 -> 冒泡
document.getElementById('outer').addEventListener('click', () => {
  console.log('outer 捕获');
}, true);

document.getElementById('outer').addEventListener('click', () => {
  console.log('outer 冒泡');
}, false);

document.getElementById('inner').addEventListener('click', () => {
  console.log('inner 捕获');
}, true);

document.getElementById('inner').addEventListener('click', () => {
  console.log('inner 冒泡');
}, false);

// 点击 inner 输出顺序:outer 捕获 -> inner 捕获 -> inner 冒泡 -> outer 冒泡

DOM3 级事件

在 DOM2 基础上扩展了更多事件类型,并允许自定义事件。

// DOM3 新增的事件类型
// UI 事件:load、scroll、resize
// 焦点事件:focus、blur、focusin、focusout
// 鼠标事件:click、dblclick、mouseenter、mouseleave
// 键盘事件:keydown、keyup、keypress
// 输入事件:textInput、input
// 合成事件:compositionstart、compositionupdate、compositionend

// 自定义事件
const customEvent = new CustomEvent('myEvent', {
  detail: { message: 'Hello' },  // 传递数据
  bubbles: true,                  // 是否冒泡
  cancelable: true                // 是否可取消
});

const element = document.getElementById('target');

element.addEventListener('myEvent', (e) => {
  console.log(e.detail.message); // 'Hello'
});

// 触发自定义事件
element.dispatchEvent(customEvent);

三者对比

特性DOM0DOM2DOM3
绑定方式属性赋值addEventListeneraddEventListener
多个处理函数❌ 覆盖✅ 支持✅ 支持
事件捕获
移除事件赋值 nullremoveEventListenerremoveEventListener
自定义事件

关键点

  • DOM0 通过属性绑定,同一事件只能有一个处理函数
  • DOM2 引入 addEventListener,支持多个处理函数和事件捕获/冒泡
  • DOM3 扩展了事件类型,支持 CustomEvent 自定义事件
  • 事件流顺序:捕获阶段 → 目标阶段 → 冒泡阶段
  • removeEventListener 必须传入相同的函数引用才能移除