讲解

浏览器把 HTML 文档解析成一棵对象树——DOM(文档对象模型),JavaScript 通过 DOM API 读写这棵树,页面随之更新。树的根是 document 对象,每个 HTML 标签是元素节点,标签里的文字是文本节点。前端开发的核心工作可以概括成:找到节点、读节点、改节点。

找节点的方法按优先级记三个:document.querySelector('CSS选择器') 返回第一个匹配元素,document.querySelectorAll('选择器') 返回所有匹配的静态 NodeList(可 forEach,但不是数组,要 [...list] 转换后再用 map);老方法 getElementById、getElementsByClassName 返回「活」的集合且 API 零散,新代码统一用 querySelector 系。选择器语法就是 CSS 那套:'#id'、'.class'、'div > p'、'[data-role="x"]'。

读改节点的常用属性:textContent 读写纯文本(安全,不解析 HTML)、innerHTML 读写 HTML 字符串(强大但有 XSS 风险,插入用户输入时危险)、value 读写表单控件的值、getAttribute/setAttribute 操作 HTML 属性、dataset 读写 data-* 自定义属性(el.dataset.userId 对应 data-user-id)、classList 增删查类名(add/remove/toggle/contains)、style 内联样式。查不到元素时 querySelector 返回 null,调用方法前记得判空。

示例

DOM 操作需要真实网页环境,以下代码请在浏览器页面上运行(按 F12 打开控制台):

<!-- 示例页面结构 -->
<ul id="todo-list">
  <li class="item" data-id="1">学习 DOM</li>
  <li class="item" data-id="2">练习查询</li>
</ul>
<input id="new-item" placeholder="新事项" />
// 查询
const list = document.querySelector('#todo-list');
const items = document.querySelectorAll('.item');
console.log('找到', items.length, '个事项');

// 读内容
console.log(list.textContent); // 所有文本拼起来
console.log(items[0].dataset.id); // '1',读 data-id

// 改内容:textContent 安全,innerHTML 会解析标签
items[0].textContent = '学习 DOM(已修改)';
// items[0].innerHTML = '<strong>加粗</strong>'; // 需要 HTML 时才用

// 表单值
const input = document.querySelector('#new-item');
input.value = '买牛奶';
console.log('输入框当前值:', input.value);

// 类名操作
items[1].classList.add('done');
items[1].classList.toggle('highlight');
console.log(items[1].className);

// 查不到返回 null,判空是习惯
const missing = document.querySelector('#not-exist');
console.log(missing); // null
missing?.classList.add('x'); // 可选链防报错

常见坑

  • 脚本在 DOM 加载前执行: 里不带 defer 的脚本运行时元素还不存在,querySelector 返回 null。脚本放 body 末尾或加 defer。
  • 把 NodeList 当数组:querySelectorAll 的结果没有 map/filter,先 [...list] 展开再链式调用。
  • 用 innerHTML 拼用户输入:innerHTML = comment 会让 或 onerror 属性的注入代码执行,经典 XSS 入口。用户内容一律 textContent。
  • 缓存了「活集合」的长度却当静态用:getElementsByClassName 返回的 HTMLCollection 会随 DOM 变化实时更新,遍历中删元素会跳项;querySelectorAll 的静态 NodeList 没这个问题。

小结

DOM 是文档的对象树;querySelector(All) 用 CSS 选择器找节点;textContent/innerHTML/value/dataset/classList 读写节点。下一章学习增删节点:DOM 操作。