Skip to content

浏览器与 DOM 操作

浏览器不仅执行 JavaScript,还提供了一组与页面、地址、设备和网络交互的 Web API。先区分职责,再写 DOM 代码,能避开许多偶发问题。

先分清四个常用对象

对象负责什么常见用途
window浏览器窗口与全局环境定时器、视口大小、历史记录
document当前页面的 DOM 树查询、创建、更新元素
location当前 URL读取查询参数、跳转页面
navigator浏览器能力和环境信息功能检测、语言偏好

屏幕尺寸不等于视口尺寸。做布局判断时,通常使用 window.innerWidthscreen.width 描述的是设备屏幕,不会随着浏览器窗口缩放而改变。

js
const params = new URLSearchParams(window.location.search)
const keyword = params.get('q')

if (keyword) {
  document.title = `搜索:${keyword}`
}

查询元素:选择最稳定的标识

querySelector 返回第一个匹配元素,querySelectorAll 返回静态的节点列表。业务脚本优先依赖语义化 class 或 data-* 属性,而不是样式层级或动态生成的 ID。

html
<button type="button" data-action="save">保存</button>
js
const saveButton = document.querySelector('[data-action="save"]')

saveButton?.addEventListener('click', saveDraft)

可选链 ?. 让“页面上不存在该元素”的情况安全退出,但不应该用它掩盖页面结构配置错误。关键元素缺失时,应在开发环境中明确报错。

更新内容:默认使用 textContent

API是否解析 HTML使用建议
textContent展示普通文本的默认选择
innerHTML仅在内容可信且确实需要 HTML 时使用
classList不涉及切换视觉状态
setAttribute不涉及更新语义和可访问性属性

不要将来自用户、接口或 URL 的内容直接赋给 innerHTML,这会带来 XSS 风险。

js
function setSaveState(button, saving) {
  button.disabled = saving
  button.textContent = saving ? '保存中…' : '保存'
  button.setAttribute('aria-busy', String(saving))
}

创建元素比拼接字符串更安全

当列表项需要交互时,用 DOM API 创建元素,数据和结构会保持分离。

js
function createTodoItem(todo) {
  const item = document.createElement('li')
  item.dataset.id = todo.id

  const label = document.createElement('span')
  label.textContent = todo.title

  item.append(label)
  return item
}

用事件委托处理动态列表

把监听器绑定在稳定的父元素上,通过 event.target.closest() 找到真正的操作按钮。后续新插入的子项无需重新绑定事件。

js
document.querySelector('#todo-list')?.addEventListener('click', (event) => {
  const button = event.target.closest('[data-action]')
  if (!button) return

  const item = button.closest('li')
  if (button.dataset.action === 'remove') {
    item?.remove()
  }
})

常见错误:innerHTML 渲染外部内容导致 XSS

把接口返回或用户输入的内容直接拼进 innerHTML,是前端最经典的安全漏洞:

js
// 接口/用户输入直接进 innerHTML
list.innerHTML = `<li>${item.name}</li>`

症状:当 item.name 里含有 <img src=x onerror="steal(document.cookie)"> 这类内容时,脚本会被执行——用户 Cookie 被偷、页面被注入恶意弹窗、或后台数据被静默篡改。更隐蔽的是,内容含 <& 时,列表结构本身会被破坏(标签被错误解析)。

为什么错innerHTML 会把字符串当作 HTML 解析,外部内容里的标签和事件属性会被真实执行。浏览器无法区分"你想展示的尖括号"和"你想执行的标签"。

正确做法:纯文本一律用 textContent,它只当文字、不当标签:

js
const item = document.createElement('li')
item.textContent = item.name  // 永远安全

确需渲染富文本时,用专门的白名单净化库过滤后再赋值。原则:任何来自外部的内容,默认都不配被信任为 HTML

一份页面交互检查表

  • 用按钮触发动作、用链接导航;不要把 div 伪装成可点击控件。
  • 文本更新用 textContent,外部内容进入 HTML 前必须净化。
  • 异步操作期间同步更新 disabled、文案和 aria-busy,避免重复提交。
  • 尺寸和能力判断以功能检测为主,不要根据 User-Agent 猜浏览器类型。

为复用而记录,为理解而整理。