引言:文档对象模型的重要性
在Web开发的学习旅程中,当掌握了JavaScript的基本语法和对象概念之后,下一个重要的里程碑就是学会如何与网页文档进行交互。编写网页和应用程序时,开发者最核心的需求之一就是能够以编程方式操纵文档结构,动态地改变页面内容和样式,响应用户的操作。这一切的实现都依赖于文档对象模型(DOM,Document Object Model)。
DOM是一套庞大的API集合,它大量使用了Document对象,为开发者提供了控制HTML结构和样式信息的标准化接口。通过DOM,JavaScript得以将静态的HTML文档转变为一个可编程操作的对象结构,使得页面不再是固定不变的,而是可以根据用户行为、数据变化或任何其他条件动态更新。
一、Web浏览器的重要部分:理解全局上下文
Web浏览器是一个非常复杂的软件系统,由许多活动部件协同工作。出于安全考虑,浏览器对Web开发者能够控制和操纵的部分做了严格限制——这种安全沙箱机制是Web生态健康发展的重要保障。
在浏览器的架构中,有三个最核心的部分是开发者会频繁接触的:
| 对象 | JavaScript表示 | 职责 |
|---|---|---|
| 窗口 | Window | 浏览器标签页的全局对象,所有全局变量和函数都是其成员 |
| 导航器 | Navigator | 代表浏览器状态和身份(用户代理),提供语言、在线状态等信息 |
| 文档 | Document | 加载到窗口中的页面内容的DOM表示,是DOM操作的入口 |
// Window:页面运行环境window.innerWidth;// 获取窗口宽度window.innerHeight;// 获取窗口高度// Navigator:浏览器信息navigator.language;// 用户首选语言navigator.onLine;// 浏览器是否在线// Document:页面的 DOM 入口document.title;// 页面标题
Window对象处于浏览器JavaScript环境的顶层,代表着整个浏览器页面的运行环境。Document是本文的重点,但理解三者的角色同样重要。
二、文档对象模型:树状结构的核心概念
每一个浏览器标签页中加载的文档,都由一个文档对象模型来表示。DOM是由浏览器创建的树状结构表示,将HTML文档的结构映射为节点树。
2.1 示例HTML文档
<!doctypehtml><htmllang="en-US"><head><metacharset="utf-8"/><title>Simple DOM example</title></head><body><section><imgsrc="dinosaur.png"alt="A red Tyrannosaurus Rex"/><p>Here we will add a link to the<ahref="https://www.mozilla.org/">Mozilla homepage</a></p></section></body></html>2.2 DOM树可视化
document └── html (根节点) ├── head │ ├── meta │ └── title │ └── #text: "Simple DOM example" └── body └── section ├── img └── p ├── #text: "Here we will add a link to the " └── a (href="https://www.mozilla.org/") └── #text: "Mozilla homepage"2.3 节点类型与关系术语
| 术语 | 定义 | 示例 |
|---|---|---|
| 元素节点 | 代表HTML元素 | <section>、<p>、<img> |
| 文本节点 | 代表元素的文本内容 | #text |
| 根节点 | DOM树顶层节点 | <html> |
| 父节点 | 包含其他节点的节点 | <body>是<section>的父节点 |
| 子节点 | 直接位于另一个节点内部的节点 | <img>是<section>的子节点 |
| 后代节点 | 位于另一个节点内部任意层级的节点 | <img>是<body>的后代节点 |
| 兄弟节点 | DOM树中同层级、共享同一父节点的节点 | <img>和<p>是兄弟节点 |
这些术语不仅在DOM编程中频繁出现,在CSS选择器中也有对应的概念。熟悉这些术语对于理解和编写DOM操作代码至关重要。
三、基本DOM操作:从选择到修改的完整流程
操作DOM内的元素,第一步始终是选择目标元素,并将其引用存储在一个变量中。
3.1 现代选择方法
| 方法 | 参数 | 返回值 | 说明 |
|---|---|---|---|
document.querySelector() | CSS选择器 | 单个元素 | 返回第一个匹配的元素 |
document.querySelectorAll() | CSS选择器 | NodeList | 返回所有匹配的元素集合 |
constlink=document.querySelector("a");// 选择文档中第一个 <a> 元素constallLinks=document.querySelectorAll("a");// 选择文档中所有 <a> 元素,返回 NodeList3.2 传统选择方法
document.getElementById("header");// 通过 id 选择document.getElementsByTagName("div");// 通过标签名选择document.getElementsByClassName("box");// 通过类名选择
querySelector()和querySelectorAll()是推荐的现代方法,灵活性远高于传统方法。
3.3 修改元素属性和内容
constlink=document.querySelector("a");link.textContent="Mozilla Developer Network";// 修改文本内容link.href="https://developer.mozilla.org";// 修改链接目标| 属性 | 作用 | 示例 |
|---|---|---|
textContent | 获取/设置元素的文本内容 | link.textContent = "新文字" |
href | <a>元素的链接地址 | link.href = "https://..." |
src | <img>元素的图片地址 | img.src = "photo.jpg" |
value | 表单元素的值 | input.value = "..." |
四、创建和放置新节点:动态构建页面内容
掌握了选择已有元素的方法之后,下一个关键技能是创建新元素并将它们添加到文档中。
4.1 创建元素
constsect=document.querySelector("section");constpara=document.createElement("p");para.textContent="We hope you enjoyed the ride.";此时新元素只存在于JavaScript的内存中,并没有出现在页面上。
4.2 追加到页面
sect.appendChild(para);Node.appendChild()将指定节点追加到调用者的子节点列表末尾。
4.3 创建文本节点
consttext=document.createTextNode(" — the premier source for web development knowledge.",);constlinkPara=document.querySelector("p");linkPara.appendChild(text);Document.createTextNode()创建纯文本节点,适用于需要保留元素内已有内容、只追加新文本的场景。
4.4 DOM操作三步走模式
① createElement("标签名") → 在内存中创建元素 ② textContent = "内容" → 设置元素文本 ③ parent.appendChild(el) → 添加到页面五、移动和删除元素:灵活控制DOM结构
5.1 移动元素
由于DOM中每个元素只能存在于一个位置,将已有元素appendChild()到另一个父节点时,它会自动从原位置移动到新位置。
sect.appendChild(linkPara);// linkPara 从原来的位置移动到 sect 的底部
linkPara持有的是该元素的唯一实例引用,appendChild()操作的是同一个元素,不是复制。如需复制,使用Node.cloneNode()。
5.2 删除元素
| 方法 | 语法 | 兼容性 |
|---|---|---|
Node.removeChild() | parent.removeChild(child) | 所有浏览器 |
Element.remove() | element.remove() | 现代浏览器 |
| 传统兼容写法 | element.parentNode.removeChild(element) | 所有浏览器 |
// 方式一:通过父节点删除(需持有父节点引用)sect.removeChild(linkPara);// 方式二:元素自己移除(现代写法)linkPara.remove();// 方式三:传统兼容写法linkPara.parentNode.removeChild(linkPara);六、操作样式:JavaScript与CSS的协作之道
6.1 方式一:直接操作 style 属性(内联样式)
para.style.color="white";para.style.backgroundColor="black";para.style.padding="10px";para.style.width="250px";para.style.textAlign="center";CSS属性名 → JavaScript属性名转换规则:去掉连字符,将连字符后的字母大写。
| CSS属性名 | JavaScript属性名 |
|---|---|
background-color | backgroundColor |
text-align | textAlign |
font-size | fontSize |
margin-top | marginTop |
⚠️ 混淆两种命名方式是初学者常见错误。
6.2 方式二:操作 class 属性(推荐)
将样式定义保留在CSS中,JavaScript只负责切换类名,实现样式和行为分离。
/* CSS 文件 */.highlight{color:white;background-color:black;padding:10px;width:250px;text-align:center;}// JavaScript 文件para.setAttribute("class","highlight");6.3 两种方式对比
| 维度 | element.style | 切换class |
|---|---|---|
| 维护性 | ❌ 样式散落在JS中 | ✅ CSS集中管理 |
| 关注点分离 | ❌ 混合 | ✅ 分离 |
| 适用场景 | 运行时动态计算的值 | 预定义的样式变体 |
| 优先级 | 内联样式(最高) | 样式表中的规则 |
七、实战项目:动态购物清单应用
让我们通过构建一个动态购物清单应用来综合运用所学的DOM操作技能。
7.1 需求分析
| 功能 | 描述 |
|---|---|
| 添加项目 | 用户在输入框中输入购物项目,点击按钮后添加到清单 |
| 删除项目 | 每个清单项旁有删除按钮,点击可移除该项目 |
| 自动清空 | 添加项目后输入框自动清空并重新获得焦点 |
7.2 获取DOM引用
constlist=document.querySelector("ul");constinput=document.querySelector("input");constbutton=document.querySelector("button");7.3 添加按钮的点击处理
button.addEventListener("click",()=>{constmyItem=input.value;// ① 先保存输入值input.value="";// ② 再清空输入框⚠️ 顺序很重要:必须先保存值再清空,否则会丢失用户输入的内容。
7.4 创建DOM元素并组装
constlistItem=document.createElement("li");constlistText=document.createElement("span");constlistBtn=document.createElement("button");listItem.appendChild(listText);listText.textContent=myItem;listItem.appendChild(listBtn);listBtn.textContent="Delete";list.appendChild(listItem);生成的HTML结构:
<li><span>用户输入的项目名</span><button>Delete</button></li>7.5 删除功能
listBtn.addEventListener("click",()=>{list.removeChild(listItem);});7.6 焦点管理
input.focus();// 输入框重新获得焦点});7.7 完整代码
constlist=document.querySelector("ul");constinput=document.querySelector("input");constbutton=document.querySelector("button");button.addEventListener("click",()=>{constmyItem=input.value;input.value="";constlistItem=document.createElement("li");constlistText=document.createElement("span");constlistBtn=document.createElement("button");listItem.appendChild(listText);listText.textContent=myItem;listItem.appendChild(listBtn);listBtn.textContent="Delete";list.appendChild(listItem);listBtn.addEventListener("click",()=>{list.removeChild(listItem);});input.focus();});执行流程图:
用户点击添加按钮 ↓ ① 保存 input.value → myItem ② 清空 input.value = "" ③ 创建 <li>、<span>、<button> ④ 设置 span.textContent = myItem ⑤ 设置 button.textContent = "Delete" ⑥ 组装:<li> → <span> + <button> ⑦ 添加到 <ul> ⑧ 为 button 绑定删除事件 ⑨ input.focus()总结
| 知识点 | 核心内容 |
|---|---|
| DOM本质 | HTML文档的树状结构表示,可编程操作的对象模型 |
| 浏览器三核心 | Window(全局环境)、Navigator(浏览器信息)、Document(DOM入口) |
| 现代选择方法 | querySelector()选单个,querySelectorAll()选所有 |
| 创建元素 | createElement()内存中创建,appendChild()添加到页面 |
| 移动元素 | appendChild()操作同一实例,自动从原位置移动 |
| 删除元素 | parent.removeChild(child)或element.remove() |
| 样式操作 | element.style设置内联样式,切换class更推荐 |
| CSS属性转换 | background-color→backgroundColor(小驼峰) |
| 实战模式 | 选择 → 创建 → 设置 → 组装 → 追加 → 事件绑定 |
掌握了这些基础能力后,开发者就具备了构建动态交互式网页的基本功。DOM编程的核心在于理解文档是一个可编程操作的对象结构——每一个HTML元素、每一段文本都是一个节点,JavaScript可以通过标准化的API来访问和修改这些节点。
还在为 JavaScript 代码写得像“意大利面条”、逻辑混乱难以维护而头秃?收藏本文持续跟进,后续将系统分享 JS 高效语法糖、浏览器兼容与 Polyfill 实战、手写核心源码解析、常见坑点避雷指南,从基础语法到进阶逻辑一站式打通,助你快速提升前端开发硬实力!