MDN 提供的 JavaScript DOM 操作标准示例有哪些

作者:窗边听雨

时间:2026-10-30

浏览:329

全面梳理 MDN Web Docs 中推荐的 JavaScript DOM 操作标准示例,涵盖元素查找、节点创建挂载、属性与类名管理、事件委托及官方经典 Shopping List 范例。

文章目录
在 Web 前端开发中,MDN Web Docs(Mozilla 开发者网络)被公认为权威的 Web 标准参考资料。本文系统梳理 MDN 在“文档对象模型(DOM)操作”与“Manipulating documents”教程中提供的核心标准示例,覆盖元素检索、节点动态增删、属性与类名响应、事件委托分发,以及官方最具代表性的完整实战范例“动态购物清单”。通过这些标准示例,帮助开发者掌握符合现代 Web 规范的原生 JavaScript DOM 编程方式。

一、DOM 树模型与标准节点认知

在深入具体代码前,MDN 首先通过结构模型向开发者阐明:浏览器在解析 HTML 文档后,会将其转换为由节点(Node)构成的树状层次结构,即 DOM 树。在 JavaScript 中,所有页面元素、文本内容甚至属性都是这棵树上的一个节点。

理解标准 DOM 操作的核心,在于明确不同节点类型之间的职责。Document 是整棵树的访问入口,Element(元素节点)负责承载 HTML 标签与布局结构,而标签内部的纯文字则被封装在 Text(文本节点)中。MDN 强调,现代 DOM 操作的一大准则是区分“元素操作”与“纯文本注入”,从而在根源上避免安全缺陷。

MDN 提供的 JavaScript DOM 操作标准示例有哪些
图 1:DOM 树的层次结构与节点类型映射关系

二、标准示例一:元素查询与选择范式

在 MDN 文档体系中,检索页面元素被归类为所有交互的第一步。在早期的 JavaScript 教学中,经常能看到 document.getElementById() 与 document.getElementsByTagName()。而在现代 MDN 标准教程中,推荐采用统一基于 CSS 选择器语法的 querySelector 系列 API。

1. 单个与多个元素的标准查询

当需要匹配页面中符合规则的第一个元素时,使用 document.querySelector();当需要批量匹配所有符合规则的元素时,使用 document.querySelectorAll()。

// 1. 匹配 ID 选择器(返回符合条件的第一个 Element,未找到返回 null)
const heading = document.querySelector('#main-heading');

// 2. 匹配类选择器或复合选择器
const submitBtn = document.querySelector('button.btn-primary');

// 3. 批量匹配元素(返回静态 NodeList 集合)
const items = document.querySelectorAll('ul.todo-list > li');

// 标准遍历 NodeList
items.forEach((item, index) => {
  console.log(`第 ${index + 1} 项内容: ${item.textContent}`);
});
易混淆点辨析:querySelectorAll 返回的 NodeList vs getElementsByClassName 返回的 HTMLCollection

许多初学者常疑惑:既然旧方法 getElementsByClassName() 执行性能略快,为什么 MDN 仍全面推荐 querySelectorAll()?

原因在于“实时性(Live)”带来的遍历陷阱。getElementsByClassName() 返回的是动态 HTMLCollection,当在循环体内向页面增删带有该类名的元素时,集合长度(length)会随之动态改变,极易引发死循环或索引漂移。而 querySelectorAll() 返回的是静态快照(Static NodeList),并且原生支持 .forEach() 迭代方法,逻辑可预测性更强。

三、标准示例二:节点的动态创建、配置与挂载

MDN 在“动态操作页面(Manipulating documents)”教学中,给出了极其严格且通用的节点创建流程,通常遵循四步法:创建孤岛节点 → 配置属性与文本 → 绑定必要事件 → 挂载至主文档树。

MDN 提供的 JavaScript DOM 操作标准示例有哪些
图 2:MDN 经典 DOM 动态创建与挂载的标准四步法

2. 基础创建示例:动态生成列表项

// 获取目标容器
const listContainer = document.querySelector('#product-list');

// 1. 创建 <li> 节点
const newListItem = document.createElement('li');

// 2. 设置内容与属性
newListItem.textContent = '高质量降噪耳机';
newListItem.classList.add('list-item', 'active');
newListItem.setAttribute('data-id', 'sku-1002');

// 3. 挂载到容器中
listContainer.appendChild(newListItem);

3. 现代 API 扩展:appendChild 与 append 的标准选择

在传统示例中,MDN 使用 Node.appendChild()。而在现代规范更新后,MDN 同步引入了 Element.append(),两者存在明确的特性差异:

  • appendChild() 仅接受一个 Node 对象,并返回被追加的该节点。
  • append() 支持同时传入多个参数,不仅支持 Node 节点,还直接支持插入字符串(内部会自动转换为 Text 节点),且没有返回值。
// 现代 append() 标准语法:一次性插入多个元素与文本
const badge = document.createElement('span');
badge.textContent = '热销';
badge.className = 'badge';

// 同时追加 DOM 节点与文本内容
newListItem.append(badge, '(限时特惠中)');

4. 批量插入优化示例:DocumentFragment

当需要连续插入成百上千个节点时,若每次循环都直接调用 container.appendChild(),会导致浏览器频繁触发重排(Reflow)与重绘(Repaint)。MDN 在性能优化指导中给出的标准范例是使用轻量级的文档片段:document.createDocumentFragment()。

const fragment = document.createDocumentFragment();
const dataList = ['JavaScript', 'TypeScript', 'Node.js', 'Web API'];

dataList.forEach((tech) => {
  const li = document.createElement('li');
  li.textContent = tech;
  fragment.appendChild(li); // 此时仍在内存中操作,不引起页面重绘
});

// 将包含所有子节点的 fragment 一次性挂载至主树
listContainer.appendChild(fragment);

四、标准示例三:内容注入安全性与 innerHTML 辨析

在 DOM 操作教学中,如何更新容器内部内容是一个不可回避的问题。MDN 在其安全指南与 DOM 教程中明确指出了 innerHTML 与 textContent 的边界。

MDN 提供的 JavaScript DOM 操作标准示例有哪些
图 3:innerHTML 与 createElement + textContent 的运作机制与安全性对比
写作辨析:是否必须完全废弃 innerHTML?

许多教程常常提出“永远不要使用 innerHTML”的论断,这一说法看似正确,但不够严谨。MDN 给出的客观建议是:

  • 什么时候可以使用:当内容是硬编码的静态 HTML 片段,且内部不需要维持事件绑定时,或者用来一行代码清空容器(element.innerHTML = ''),此时使用 innerHTML 是极为简练高效的。
  • 什么时候严禁使用:凡是内容中混入了来自输入框、URL 参数、服务端未受信任返回的动态字符串,严禁直接拼接进 innerHTML,必须改用 textContent 或 document.createTextNode()。

五、标准示例四:属性控制与 classList 样式管理

修改元素样式和状态是 DOM 操作中最频繁的需求。MDN 强调将“结构、样式与行为解耦”,反对在 JavaScript 中大段编写行内 style 属性。

1. 标准类名控制器:classList

MDN 规范指出,控制样式的最佳实践是在 CSS 文件中预定义好类选择器,并在 JavaScript 中通过 Element.classList 接口来增删状态类。

const panel = document.querySelector('.info-panel');

// 添加样式类
panel.classList.add('visible', 'highlight');

// 移除样式类
panel.classList.remove('hidden');

// 切换样式类(存在则移除,不存在则添加)
panel.classList.toggle('active');

// 条件式切换(第二个布尔参数:true 时添加,false 时移除)
const isOnline = checkConnection();
panel.classList.toggle('online-mode', isOnline);

// 判断是否包含特定样式类
if (panel.classList.contains('visible')) {
  console.log('面板正处于展示状态');
}

2. 自定义数据属性的标准读取:dataset

HTML5 允许在元素上定义以 data- 为前缀的自定义属性。MDN 示例展示了如何使用 dataset 接口实现 JavaScript 与 HTML 标记的解耦传参:

// HTML: <div id="user" data-user-id="9527" data-role-type="admin"></div>
const userEl = document.querySelector('#user');

// 读取属性(kebab-case 自动映射为 camelCase 驼峰命名)
console.log(userEl.dataset.userId);   // 输出: "9527"
console.log(userEl.dataset.roleType); // 输出: "admin"

// 写入或更新自定义属性
userEl.dataset.status = 'active'; // 相当于添加 data-status="active"

六、标准示例五:事件监听与高效“事件委托”范式

响应用户交互是 DOM 编程的核心。MDN 在“Introduction to events”章节中彻底规范了事件绑定的标准写法,即使用 EventTarget.addEventListener()。

1. 基础事件监听规范

MDN 强烈建议避免使用 HTML 内联 onclick="..." 或 DOM0 级属性 element.onclick = fn,因为它们无法为一个事件附加多个监听器,且容易造成覆盖。

const actionBtn = document.querySelector('#submit-action');

function handleClick(event) {
  // 阻止表单默认提交刷新
  event.preventDefault();
  console.log('点击按钮触发:', event.target);
}

// 绑定标准监听
actionBtn.addEventListener('click', handleClick);

// 在必要时精确移除监听(必须引用同一个具名函数)
// actionBtn.removeEventListener('click', handleClick);

2. 经典进阶示例:事件冒泡与事件委托(Event Delegation)

在处理动态列表或大量子元素(如几十个表格行、列表项)时,若为每个子元素单独调用 addEventListener,不仅浪费内存,而且动态新增的子项将无法响应事件。

MDN 提供的标准解法是利用 DOM 的事件冒泡(Event Bubbling)机制:将监听器绑定在公共父级容器上,通过 event.target 判断真正被点击的子元素。

const parentList = document.querySelector('#dynamic-list');

// 只在父容器上绑定一次点击监听
parentList.addEventListener('click', (event) => {
  // 使用 Element.closest() 准确定位被点击项是否属于目标列表项
  const targetItem = event.target.closest('li.list-item');
  
  if (!targetItem || !parentList.contains(targetItem)) {
    return; // 点击落在列表外部或空白区域,忽略
  }

  // 判断是否点击了删除按钮
  if (event.target.matches('button.delete-btn')) {
    targetItem.remove(); // 直接调用现代 Element.remove() 移除节点
    console.log('已成功删除列表项');
  } else {
    targetItem.classList.toggle('selected');
  }
});

七、MDN 官方经典综合示例:Shopping List 实战剖析

在 MDN 教程的“Manipulating documents”章节末尾,官方提供了一个标志性的实战综合演练——动态购物清单(Shopping List)。该范例紧凑而完整地组合了输入框读取、节点动态构建、嵌套结构挂载、事件驱动删除以及交互焦点管理。

1. 完整的 HTML 结构骨架

<div class="shopping-app">
  <h1>我的购物清单</h1>
  <div class="input-group">
    <label for="item-input">输入商品名:</label>
    <input type="text" id="item-input" placeholder="例如:鲜牛奶" />
    <button id="add-btn">添加到清单</button>
  </div>
  <ul id="shopping-list"></ul>
</div>

2. MDN 官方标准 JavaScript 逻辑实现

// 1. 获取核心 DOM 引用
const list = document.querySelector('#shopping-list');
const input = document.querySelector('#item-input');
const button = document.querySelector('#add-btn');

// 2. 绑定添加事件处理函数
button.addEventListener('click', () => {
  const itemText = input.value.trim();

  // 空值校验
  if (itemText === '') {
    input.focus();
    return;
  }

  // 3. 动态创建列表项及子组件
  const listItem = document.createElement('li');
  const textSpan = document.createElement('span');
  const deleteBtn = document.createElement('button');

  // 4. 组装子节点内容
  textSpan.textContent = itemText;
  deleteBtn.textContent = '删除';
  deleteBtn.className = 'delete-item-btn';

  // 5. 建立层级关系
  listItem.append(textSpan, deleteBtn);

  // 6. 为新建节点的删除按钮绑定专属销毁逻辑
  deleteBtn.addEventListener('click', () => {
    // 现代标准 API: 直接调用 element.remove()
    listItem.remove();
  });

  // 7. 挂载到主列表,清空输入框并重置焦点
  list.appendChild(listItem);
  input.value = '';
  input.focus();
});
Shopping List 范例展现的 MDN 标准工程习惯
  1. 焦点闭环(Focus Loop):添加或点击删除后,显式调用 input.focus(),极大地提升了无障碍(Accessibility)体验与键盘操作连贯性。
  2. 空值过滤与清理:通过 .trim() 防御纯空格无意义数据。
  3. 声明式结构组装:先使用 createElement 逐个创建 li、span、button,再通过层级关系进行安全挂载,绝不使用脆弱的 HTML 字符串拼接。

八、MDN DOM 操作核心 API 与最佳实践全景总结

综观 MDN Web Docs 提供的所有 DOM 教学与参考指南,其标准示例的设计哲学可以归纳为四大原则:CSS 选择器统一化、节点构建安全化、交互逻辑委托化、样式表现类名化。下方的总结矩阵清晰展示了各核心任务下的推荐 API 与技术要点。

MDN 提供的 JavaScript DOM 操作标准示例有哪些
图 4:MDN DOM 操作核心 API 与最佳实践矩阵全貌

常见操作 API 速查表

操作领域 现代 MDN 推荐写法 早期/易混淆写法 主要优势与推荐理由
元素查找 querySelector() / querySelectorAll() getElementById() / getElementsByTagName() 统一选择器语法,返回静态 NodeList,支持 forEach 迭代,无动态变动隐患。
内容插入 createElement() + textContent innerHTML = ... 拼接 自动转义纯文本,天然免疫 XSS 漏洞,保留容器内既有 DOM 节点与事件绑定。
节点挂载 parent.append(el1, el2) parent.appendChild(el1) 可一次性传入多个节点及字符串,语法更现代化、更灵活。
样式管理 el.classList.add() / toggle() el.style.cssText = ... 将表现形式交给 CSS 集中管理,JS 仅负责状态开关,保持代码高可维护性。
节点删除 element.remove() parent.removeChild(element) 节点直接调用自我删除,无需冗余获取 parentNode 引用。
事件交互 父级 addEventListener (事件委托) 给每个子元素遍历绑定 onclick 大幅降低内存占用,且能天然支持后续动态新增子项的点击响应。

掌握 MDN 提供的这些标准示例,能够让开发者在脱离各类前端框架(如 React、Vue)的情况下,编写出执行效率高、代码结构健壮且符合 Web 安全规范的原生 JavaScript 应用。这些标准范式同样是深入理解现代框架虚拟 DOM 与响应式渲染机制的坚实基石。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章