DOM 查询与安全更新:选择器、文本节点和事件清理
本文目录
浏览器原生 DOM API 已覆盖多数选择、更新和事件需求。旧代码常用历史集合接口、假占位文本和 innerHTML 处理普通文案;现代实现应优先使用语义元素、文本 API 和明确的生命周期。
查询元素和集合差异
getElementById 查单个 ID;querySelector 返回第一个匹配元素或 null;querySelectorAll 返回静态 NodeList。getElementsByTagName 和部分旧集合接口返回 live HTMLCollection,DOM 变化后集合内容会随之变化。遍历时删除节点可能让 live 集合的索引跳过元素,因此先取静态快照或按正确方向迭代。
查找之后先处理不存在情况,不要假设元素一定已加载。ES module 与 defer 脚本会在 HTML 解析后执行;非延迟脚本放在 head 中时,可用 DOMContentLoaded 或把脚本移动到合理位置。SSR/hydration 则应遵循框架生命周期,不要在服务端访问 document。
用户文本用 textContent
textContent 读写文本节点,不会将标签解析成可执行 HTML;innerText 更接近视觉显示文本,计算时可能受样式与布局影响。innerHTML 是 HTML sink:它能解析标记,也会扩大 XSS 风险。只有确实需要显示富文本,并且 HTML 已经通过维护中的 sanitizer 与严格 allowlist 清理时才使用它。
搜索框提示优先用 HTML placeholder,不要把提示文字当成真实 value 再靠 focus/blur 清空;value 属于用户数据,应该由用户输入和表单状态控制。
const output = document.querySelector('[data-output]');
if (output) output.textContent = untrustedMessage;
const item = document.createElement('li');
item.textContent = userProvidedTitle;
document.querySelector('[data-list]')?.append(item);
设置 URL、事件处理器或样式等特殊属性时,使用相应 DOM 属性并先做 allowlist 验证。任意对象键或用户输入不要拼入 attribute 名称、选择器、CSS 或 HTML 字符串。自定义数据可放入 data-*,通过 dataset 读取,但 dataset 仍是不可信字符串。
事件监听要有所有者
为每个元素分别注册监听器在小页面可读,但列表应优先评估父节点事件委托。使用 addEventListener 可以配合 once、passive、capture 和 AbortSignal;组件销毁或功能关闭时,用对应清理函数或 AbortController 移除监听。
const controller = new AbortController();
const list = document.querySelector('[data-list]');
list?.addEventListener('click', (event) => {
if (!(event.target instanceof Element)) return;
const action = event.target.closest('[data-action]');
if (!action || !list.contains(action)) return;
runAction(action.dataset.action);
}, { signal: controller.signal });
// 页面/组件退出时:
controller.abort();
键盘操作应使用 button、a、input 等语义元素,并检查 Tab 顺序、焦点、Enter/Space 行为。hover/mouse 不是唯一输入通道。查询 DOM 或操作节点也不会替代框架状态;在 React/Vue 等受控 UI 中避免绕过框架写入由它管理的节点。
检查清单
- 查询结果是否可能是 null,集合是 live 还是静态?
- 普通文本是否进入
textContent,而不是拼接到 HTML? - 是否误将 placeholder 展示值保存为业务数据?
- 事件监听是否可取消,是否存在重复注册或闭包持有旧节点?
- 用户能否用键盘和辅助技术完成相同动作?
参考:MDN Document.querySelector、MDN querySelectorAll、MDN textContent、MDN addEventListener、MDN DOMContentLoaded、Vue Security。
Live Notes
留言提交后会先进入审核,审核通过后对其他读者公开。