浏览器原理 · 18/51
1. addEventListener 第三个参数 2. addEventListener 与 attachEvent 区别 3. 浏览器兼容性测试与内核 4. 浏览器兼容性问题 5. 浏览器内核与引擎 6. 浏览器图层创建条件 7. 浏览器多进程架构 8. 浏览器渲染机制 9. 浏览器存储方案 10. 浏览器版本检测方法 11. children 与 childNodes 区别 12. 常见浏览器兼容性问题 13. Chrome 页面进程数量 14. 坐标系统对比 15. 多标签页通讯方案 16. 删除 Cookie 17. 自定义事件 18. DOM 事件处理方式演进 19. 元素尺寸属性对比 20. DOM 节点操作 21. DOM 事件机制 22. addEventListener 与 attachEvent 的区别 23. 获取页面所有复选框 24. HTMLCollection 与 NodeList 区别 25. Hybrid 应用开发 26. 强缓存命中机制 27. 浏览器缓存机制 28. 页面编码与资源编码不一致处理 29. jQuery 事件绑定方法对比 30. Input 点击触发的事件顺序 31. JavaScript 浏览器兼容性问题 32. jQuery 多事件绑定实现 33. JSBridge 原理 34. 链接点击后 Hover 失效解决方案 35. 减少重绘和回流的性能优化 36. 移动端 300ms 点击延迟问题 37. 移动端视口配置 38. 移动端点击穿透问题解决 39. 移动端兼容性问题 40. JSBridge 原理与实现 41. 移动端 1px 像素问题解决方案 42. 浏览器渲染流程 43. 页面加载完成事件对比 44. Offset、Scroll、Client 属性对比 45. 同源策略与跨域解决方案 46. Script 标签位置对页面加载的影响 47. Service Worker 与 PWA 48. 存储方案对比:Cookie、Storage、IndexedDB 49. 强缓存默认时间 50. URL 到页面显示的完整过程 51. V8 引擎 JavaScript 执行过程

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 必须传入相同的函数引用才能移除