Web 前端手册WEB FRONTEND

CHAPTER 03应用层 · DOM

DOM 与事件

选择器、事件委托、BOM、表单与拖拽。理解浏览器如何把文档变成可编程的对象树。

开始阅读难度中级先修第一、二章约2小时
03.1

DOM 树与选择器

DOM 把 HTML 解析成节点树。querySelector / querySelectorAll 用 CSS 选择器查找;getElementById 最快但只按 id。

const el = document.querySelector('#app .title');
const items = document.querySelectorAll('li');
items.forEach(li => console.log(li.textContent));
缓存选择器

频繁访问的节点先存为变量,别在每次事件里反复 querySelector,省去重复查找开销。

03.2

增删改节点

用 createElement 创建、append/prepend 插入、remove 删除、classList 管理类。操作应批量、最小化重排。

const li = document.createElement('li');
li.textContent = '新项';
li.classList.add('item');
list.append(li);
// 批量用 DocumentFragment 减少重排
const frag = document.createDocumentFragment();
03.3

事件模型

事件流分三阶段:捕获(外层向内)、目标、冒泡(内层向外)。addEventListener 默认在冒泡阶段触发,stopPropagation 可阻止继续。

el.addEventListener('click', handler);
el.addEventListener('click', captureHandler, true); // 捕获阶段
// e.stopPropagation() 阻止冒泡;e.preventDefault() 阻止默认行为
不该滥用 stopPropagation

它会阻断冒泡,可能影响其他合法监听器。仅在确有需要时(如模态内点击不关闭)使用。

03.4

事件委托

把子元素的事件监听挂到父容器,利用冒泡统一处理。新增/删除子节点无需单独绑定,性能好、易维护。

list.addEventListener('click', (e) => {
  const li = e.target.closest('li');   // 找到实际命中的 li
  if (!li) return;
  console.log('点了', li.dataset.id);
});
03.5

BOM 与存储

window/location/history 提供浏览器能力;localStorage(持久)/ sessionStorage(会话)做简单客户端存储。

localStorage.setItem('token', t);
const t = localStorage.getItem('token');
history.pushState({}, '', '/detail/1');   // 不刷新改 URL
存敏感信息?

localStorage 可被 XSS 读取,绝不能存 token/密码。鉴权信息用 HttpOnly Cookie 更安全。

03.6

表单处理

用 form 的 submit 事件统一处理,FormData 收集字段,配合原生校验属性(required/pattern)提升体验。

form.addEventListener('submit', (e) => {
  e.preventDefault();
  const data = new FormData(form);
  console.log(data.get('email'));
});
03.7

拖拽与文件

HTML5 拖拽用 drag/drop 事件;文件上传通过 <input type="file"> 或拖放,用 FileReader/URL.createObjectURL 读取。

dropZone.addEventListener('drop', (e) => {
  e.preventDefault();
  const file = e.dataTransfer.files[0];
  const url = URL.createObjectURL(file);  // 预览
});
03.8

常见陷阱与 FAQ

为什么事件监听不生效?

最常见是脚本在 DOM 解析前执行。把脚本放 body 末尾、用 defer,或在 DOMContentLoaded 后绑定。

innerHTML 有风险?

拼接用户输入到 innerHTML 会造成 XSS。优先用 textContent;必须插入 HTML 时对内容做转义或使用可信模板。

频繁操作 DOM 卡顿?

多次读写布局属性会触发强制同步布局。批量修改、用 DocumentFragment、或用 requestAnimationFrame 合并。

03.9

实战练习与资源

延伸资源