JavaScript怎么操作网页元素?DOM基础用法图文详解
全面详解JavaScript如何操作网页元素。从DOM树的核心概念入手,详细讲解元素的查找获取、内容与属性读写、样式控制、动态增删节点的标准步骤与常见避坑指南,包含4幅高清内联SVG图示。
一、认识 DOM:HTML 是如何变成可编程对象的
很多初学者容易将“修改网页”误解为在 JavaScript 内部拼写或改写原始的 HTML 字符串。实际上,浏览器展现页面的第一步是解析 HTML,并在内存中构建对应的树状对象结构。在这个结构中,每个标签、属性甚至换行文本,都被转化为对应的 JavaScript 节点对象。
整个 DOM 树的最高入口是全局内置的 document 对象。只要页面加载完成,开发者就可以通过 document 提供的各种方法深入树形结构的各个层级,按需提取或操纵任意分支节点。
二、第一步:精准获取目标元素
要改变某个元素,首先必须找到它。现代 Web 开发中,最推荐且通用的选择器方法是 querySelector 和 querySelectorAll,它们支持与 CSS 选择器完全一致的语法。
1. 获取单个元素
// 通过标签名、类名、ID或复杂复合选择器查找
const mainTitle = document.querySelector('h1');
const submitBtn = document.querySelector('#btn-submit');
const activeCard = document.querySelector('.card.active');
querySelector 会返回文档中匹配指定选择器的第一个元素节点。如果页面中没有符合条件的元素,则返回 null。
2. 获取元素集合
// 获取所有匹配的元素集合
const allListItems = document.querySelectorAll('ul.todo-list > li');
// NodeList 支持直接使用 forEach 遍历
allListItems.forEach((item, index) => {
console.log(`第 ${index + 1} 个项目:`, item);
});
querySelectorAll 返回的是一个类数组对象(NodeList)。它包含了当前匹配的所有节点。即使只匹配到一个元素或没有任何匹配项,它也会返回一个 NodeList(无匹配时长度为 0),而不是 null。
document.getElementById('id') 运行速度略高,但只支持单 ID 查找;而 getElementsByClassName 返回的是动态 HTMLCollection,当 DOM 结构变化时该集合会自动更新,有时会在遍历中导致意外跳项。日常业务开发中,优先使用语法统一的 querySelector 和 querySelectorAll 能够减少绝大多数逻辑疏漏。
三、第二步:读取与修改元素的内容与属性
定位到元素之后,最常见的操作就是改变其内部展示的文字、或者调整其属性(例如图片的来源地址、链接的跳转路径、表单的输入值等)。
1. 内容读写:textContent 与 innerHTML
const noticeBox = document.querySelector('.notice');
// 推荐:读取或设置纯文本(高效、安全,自动转义特殊字符)
noticeBox.textContent = '操作已完成,请刷新查看最新数据。';
// 仅在明确需要插入子 HTML 结构时使用 innerHTML
noticeBox.innerHTML = '<strong>提示:</strong>数据已成功同步!';
辨析要点:只要不需要解析 HTML 标签,一律优先使用 textContent。如果随意把用户输入的内容拼接进 innerHTML,极易引发跨站脚本漏洞(XSS)。同时,textContent 避免了 HTML 解析器的二次解析,执行性能更优。
2. 属性读写:标准属性与自定义属性
对于大部分标准 HTML 属性,可以直接通过“节点对象.属性名”进行读取或赋值:
const avatarImg = document.querySelector('#user-avatar');
const searchInput = document.querySelector('input[type="text"]');
// 修改标准属性
avatarImg.src = 'https://example.com/avatar.jpg';
avatarImg.alt = '用户头像';
// 表单元素的值通过 .value 属性获取或设置
console.log('用户当前输入:', searchInput.value);
searchInput.value = ''; // 清空输入框
对于包含连字符的自定义属性(如 data-user-id="1024"),现代浏览器提供了优雅的 dataset 属性集合进行访问:
const userCard = document.querySelector('.user-card');
console.log(userCard.dataset.userId); // 读取 data-user-id
userCard.dataset.role = 'administrator'; // 自动添加或更新 data-role="administrator"
四、第三步:控制元素外观与样式
调整网页元素的视觉呈现通常有两种策略:一种是直接修改元素的内联样式,另一种则是切换预先定义好的 CSS 类名。在实际工程中,两者的适用边界非常清晰。
1. 为什么优先推荐使用 classList 切换类名?
将样式细节交由 CSS 文件管理,JavaScript 只负责“控制状态”(如添加 active、hidden、expanded 类),能够做到结构、表现与行为的分离,使代码清晰且便于维护。
const modal = document.querySelector('.dialog-modal');
modal.classList.add('is-open'); // 添加类
modal.classList.remove('is-hidden'); // 移除类
modal.classList.toggle('highlight'); // 存在则移除,不存在则添加
const isVisible = modal.classList.contains('is-open'); // 判断是否存在
2. 何时使用 element.style 直接修改?
当样式的数值是由运行时动态计算出来的(例如拖拽时的实时坐标 left: 235px、动态进度条的百分比宽度等)时,直接操作 element.style 是最直接的方式:
const progressBar = document.querySelector('.progress-inner');
// 属性名需转换为小驼峰命名(如 background-color 改写为 backgroundColor)
progressBar.style.width = '75%';
progressBar.style.backgroundColor = '#8a9478';
五、第四步:动态创建、挂载与移除元素
除了修改页面中已有标签,现代前端应用最频繁的需求就是按需“动态增加新元素”(例如加载更多评论、添加待办清单)和“移除旧元素”。完整的操作可以分为四个确定步骤:
- 创建新节点:使用
document.createElement('标签名')在内存中生成一个独立的空白元素。 - 装配属性与内容:为新创建的节点挂载文字、样式类、甚至绑定事件监听器。
- 定位父级挂载点:使用
querySelector找到页面中现有的容器。 - 挂载上屏:使用
appendChild()或append()将新节点装入父容器,触发浏览器渲染。
移除已有节点
当需要从界面中剔除某个元素时,现代浏览器支持直接调用节点自身的 remove() 方法:
const targetItem = document.querySelector('#item-to-delete');
if (targetItem) {
targetItem.remove(); // 直接将自己从 DOM 树中移除
}
六、实战演练:串联四大步骤的交互案例
以下示例展示了一个轻量、完整的待办事项追加与删除逻辑。它融合了“查找容器”、“读取输入”、“创建节点”、“绑定事件”和“挂载节点”的全流程:
// 1. 定位页面上的关键元素
const input = document.querySelector('#todo-input');
const addBtn = document.querySelector('#add-btn');
const todoList = document.querySelector('#todo-list');
// 2. 为按钮添加点击交互事件
addBtn.addEventListener('click', () => {
const text = input.value.trim();
if (!text) {
alert('请输入内容!');
return;
}
// 3. 内存创建新的列表项 <li>
const li = document.createElement('li');
li.className = 'todo-item';
li.textContent = text;
// 4. 创建行内删除按钮
const delBtn = document.createElement('button');
delBtn.textContent = '删除';
delBtn.className = 'btn-del';
// 5. 为删除按钮绑定独立移除逻辑
delBtn.addEventListener('click', () => {
li.remove(); // 点击时直接移除当前这一行 li
});
// 6. 组装并挂载到列表容器中
li.appendChild(delBtn);
todoList.appendChild(li);
// 7. 清空输入框并重设焦点
input.value = '';
input.focus();
});
七、初学者最常踩的三个坑
1. 脚本执行过早,获取到的元素永远是 null
如果将 <script> 标签直接放在 <head> 中,当浏览器解析到 JS 代码时,<body> 内部的 HTML 元素还没有被读取和解析。此时执行 document.querySelector 会直接返回 null,紧接着访问属性就会抛出 TypeError: Cannot read properties of null。
解决办法:在引入脚本的标签中加上 defer 属性(推荐),或将 <script> 放在 </body> 标签关闭之前,确保 DOM 树已经解析完成。
2. 在循环中频繁调用 appendChild 导致性能损耗
如果需要循环插入 100 个节点,直接在循环体内执行 100 次 parentElement.appendChild(li) 会让浏览器频繁触发重排(Reflow)。推荐使用 DocumentFragment(轻量内存文档片段)先收集所有生成的子节点,最后一次性挂载到页面上。
3. 混淆事件对象的 event.target 与绑定元素
在事件委托处理中,event.target 指向实际被鼠标点击的那个最深层子元素(如按钮内部的 <span>),而 event.currentTarget 则指向当前挂载监听器的父级元素。理解两者的区别是编写健壮交互代码的前提。
八、全文总结
操作网页元素的本质并不繁杂。牢记“先找后改、按需创挂”的执行顺序,合理选择适合具体场景的 API,在保障代码安全(防范 XSS)与性能(批量挂载与事件委托)的前提下,就能轻松应对各类日常 Web 交互开发。
anime.js 快速入门:怎么引入库并编写第一个 DOM 动画
2026-11-05 14:22:43
在线JS解密后变量名仍乱码?结合浏览器DevTools调试还原
2026-11-04 20:26:01
怎么在浏览器中运行JavaScript代码并查看输出结果
2026-11-04 09:07:33
JS 获取屏幕分辨率:window.screen.width 与 height 用法
2026-11-04 08:52:48
为什么推荐用DOMContentLoaded代替window.onload初始化JS
2026-11-04 08:42:33








