当用户打开网页时,浏览器会自动解析HTML文档,并将其构建为一个结构化的数据模型——文档对象模型(Document Object Model,简称DOM)。DOM 是HTML文档在内存中的表示方式,它以树状结构组织页面上的所有元素、文本节点及其属性,从而为开发者提供了一套标准的接口来访问和操作文档内容。
通过DOM,开发者可以使用JavaScript对页面元素进行精确的查找、读取、修改、样式变更、节点的增删等操作,实现页面内容和结构的动态更新。DOM作为Web前端开发的核心基础,使得页面具备高度的交互性和用户体验的可定制性。

在深入了解如何操作DOM之前,我们先来看看DOM是如何组织页面内容的。HTML文档中的元素是层层嵌套的,就像一棵树一样。最外层是html标签,它包含了head和body两个主要部分,而body里面又包含了标题、段落、链接等各种元素。这种嵌套关系在浏览器内部被转换成一棵真正的树形结构,我们称之为DOM树。
在这棵DOM树中,每一个HTML标签、每一段文字、甚至每个属性,都会成为一个节点。节点之间通过父子关系连接起来,形成一个完整的树状结构。最顶端的节点是文档的根节点,通常对应着html元素,然后逐层向下展开,直到最底层的文本节点。
|<!DOCTYPE html> <html> <head> <title>我的网页</title> </head> <body> <h1>欢迎</h1> <p>这是一段文字</p> </body> </html>
这段简单的HTML代码在浏览器中会被转换成这样的DOM树结构:html是根节点,它有两个子节点head和body,head里面有一个title节点,body里面有一个h1节点和一个p节点。每个节点都可以包含子节点,也可以包含文本内容。
浏览器为我们提供了一个名为document的全局对象,这个对象就是整个DOM树的入口。通过document对象,我们可以访问页面上的任何元素。比如,我们可以通过document.body来访问body元素,通过document.head来访问head元素,通过document.documentElement来访问html根元素。
|// 获取页面的根元素(html元素) let rootElement = document.documentElement; console.log("根元素标签名:", rootElement.tagName); // 访问head和body let headElement = document.head; let bodyElement = document.body; // 获取页面标题 console.log("页面标题:", document.title);
这个例子展示了如何通过document对象来访问页面的基本结构。document对象就像是一扇门,通过这扇门,我们可以进入DOM树的世界,开始探索和操作页面上的元素。
在DOM树中,不同类型的页面内容会被转换成不同类型的节点。最常见的两种节点类型是元素节点和文本节点。元素节点对应着HTML标签,比如div、p、h1等,而文本节点则对应着标签之间的文字内容。
每个节点都有一个nodeType属性,这个属性用数字来表示节点的类型。元素节点的nodeType是1,文本节点的nodeType是3。虽然还有其他类型的节点,但在日常开发中,我们最常接触的就是这两种。
|// 获取页面中的第一个段落 let paragraph = document.querySelector('p'); // 查看节点的类型 console.log("节点类型:", paragraph.nodeType); console.log("元素节点常量:", Node.ELEMENT_NODE); // 查看段落中的子节点 paragraph.childNodes.forEach((node, index) => { if (node.nodeType === Node.TEXT_NODE) { console.
通过这个例子,我们可以看到如何区分不同类型的节点。理解节点类型很重要,因为不同类型的节点有不同的属性和方法,我们在操作时需要根据节点类型来选择合适的方式。
在实际开发中,我们经常需要找到页面上的某个特定元素,然后对它进行操作。DOM为我们提供了多种查找元素的方法,每种方法都有自己的特点和适用场景。
如果页面上的某个元素有唯一的ID,我们可以使用getElementById方法来快速找到它。ID在页面中应该是唯一的,所以这个方法总是返回一个元素,或者返回null(如果找不到的话)。
|// 假设页面上有一个id为"myButton"的按钮 let button = document.getElementById('myButton'); // 检查是否找到了元素 if (button) { console.log("找到了按钮:", button); console.log("按钮文本:", button.textContent); } else { console.log("未找到该元素"); }
这个方法非常简单直接,当我们知道元素的ID时,这是最快最准确的查找方式。需要注意的是,ID选择器不需要加#号,直接传入ID名称即可。
现代浏览器提供了更强大的查找方法:querySelector和querySelectorAll。这两个方法允许我们使用CSS选择器语法来查找元素,就像在CSS中写选择器一样。querySelector返回第一个匹配的元素,而querySelectorAll返回所有匹配的元素。
|// 查找第一个段落元素 let firstParagraph = document.querySelector('p'); console.log("第一个段落:", firstParagraph.textContent); // 查找所有段落元素 let allParagraphs = document.querySelectorAll('p'); console.log("段落总数:", allParagraphs.length); // 查找具有特定类名的元素 let highlightElement = document.querySelector('.highlight'
querySelector和querySelectorAll非常灵活,它们支持所有CSS选择器语法,包括类选择器、ID选择器、属性选择器等。这使得我们可以用简洁的代码来查找复杂的元素组合。
有时候我们需要找到页面上所有相同标签的元素,比如所有的段落、所有的链接等。这时可以使用getElementsByTagName方法。
|// 查找所有段落元素 let paragraphs = document.getElementsByTagName('p'); console.log("找到", paragraphs.length, "个段落"); // 遍历所有段落 for (let i = 0; i < paragraphs.length; i++) { console.log(`段落 ${i + 1}:`, paragraphs[i].textContent);
这个方法返回的是一个类似数组的集合,我们可以通过索引来访问其中的元素,也可以使用循环来遍历所有元素。
找到元素之后,我们就可以开始修改页面内容了。DOM提供了丰富的方法来创建新元素、添加元素、删除元素,以及修改元素的文本内容。
我们可以使用createElement方法来创建一个新的HTML元素。创建元素只是第一步,创建出来的元素还不会显示在页面上,我们需要把它添加到DOM树中才能看到。
|// 创建一个新的段落元素 let newParagraph = document.createElement('p'); // 设置段落的文本内容 newParagraph.textContent = '这是新创建的段落'; // 设置段落的样式 newParagraph.style.color = 'blue'; newParagraph.style.fontSize = '18px'; // 将新段落添加到body中 document.body.appendChild(newParagraph);
这个例子展示了创建元素的基本流程:先创建元素,然后设置它的内容和样式,最后把它添加到页面上。createElement方法接受一个标签名作为参数,可以是任何HTML标签,比如div、span、button等。
创建元素后,我们需要把它添加到DOM树中才能显示出来。最常用的方法是appendChild,它会把新元素添加到指定父元素的最后一个子元素位置。
|// 创建一个容器div let container = document.createElement('div'); container.id = 'myContainer'; // 创建几个子元素 let title = document.createElement('h2'); title.textContent = '我的标题'; let content = document.createElement('p'); content.textContent = '这是内容';
appendChild方法会把元素添加到父元素的末尾。如果我们想在特定位置插入元素,可以使用insertBefore方法,它可以在指定元素之前插入新元素。
当我们不再需要某个元素时,可以使用remove方法来删除它。这个方法会从DOM树中移除元素,元素被删除后就不会再显示在页面上了。
|// 找到要删除的元素 let elementToRemove = document.getElementById('oldElement'); // 删除元素 if (elementToRemove) { elementToRemove.remove(); console.log("元素已删除"); }
删除元素非常简单,只需要调用remove方法即可。被删除的元素会从DOM树中完全移除,它的所有子元素也会一起被删除。
我们可以通过textContent或innerHTML属性来修改元素的文本内容。textContent会设置纯文本内容,而innerHTML可以设置包含HTML标签的内容。
|// 找到要修改的段落 let paragraph = document.querySelector('p'); // 使用textContent修改文本(纯文本,不会解析HTML) paragraph.textContent = '这是新的文本内容'; // 或者使用innerHTML修改内容(可以包含HTML标签) let div = document.querySelector('div'); div.innerHTML = '<strong>这是加粗的文字</strong>和普通文字';
textContent和innerHTML的区别在于,textContent会把所有内容都当作纯文本处理,即使你写了HTML标签,它也会显示为文本。而innerHTML会解析HTML标签,所以我们可以用它来添加格式化的内容。
通过JavaScript,我们可以动态地改变元素的样式,让页面根据用户的操作或程序逻辑产生视觉变化。有两种主要的方式来控制样式:直接操作style属性,或者通过添加和移除CSS类名。
每个DOM元素都有一个style属性,我们可以通过它来直接设置内联样式。这种方式设置的样式优先级很高,会覆盖CSS文件中定义的样式。
|// 找到要修改的元素 let button = document.querySelector('button'); // 修改背景颜色 button.style.backgroundColor = 'blue'; // 修改文字颜色 button.style.color = 'white'; // 修改字体大小 button.style.fontSize = '16px'; // 修改内边距 button.style.padding = '10px 20px'; // 修改边框 button.style.border = 'none'; button.style.borderRadius
通过style属性,我们可以像在CSS中一样设置各种样式属性。需要注意的是,CSS属性名在JavaScript中需要使用驼峰命名法,比如background-color要写成backgroundColor,font-size要写成fontSize。
除了直接操作style属性,更常见的做法是通过添加或移除CSS类名来改变元素样式。这种方式更利于维护,也更符合关注点分离的原则。
|// 找到要修改的元素 let card = document.querySelector('.card'); // 添加一个CSS类 card.classList.add('highlight'); // 移除一个CSS类 card.classList.remove('normal'); // 切换一个CSS类(如果存在就移除,不存在就添加) card.classList.toggle('active'); // 检查是否包含某个类 if (card.classList.contains('highlight')) { console.log
classList对象提供了丰富的方法来管理元素的CSS类。这种方式的好处是,我们可以把样式定义写在CSS文件中,然后通过JavaScript来动态地添加或移除类名,从而实现样式的切换。
在实际开发中,我们经常需要同时使用style属性和classList。比如,我们可以用classList来切换主题样式,用style来设置动态计算的值。
|// 创建一个按钮 let button = document.createElement('button'); button.textContent = '点击我'; // 添加基础样式类 button.classList.add('btn', 'btn-primary'); // 设置一些动态样式 button.style.margin = '10px'; button.style.cursor = 'pointer'; // 添加到页面 document.body.appendChild(button); // 点击时切换样式 button.
这个例子展示了如何结合使用classList和style属性。classList适合用来切换预定义的样式状态,而style适合用来设置需要动态计算的值。
让我们通过一个完整的例子来综合运用前面学到的知识。这个例子会创建一个简单的待办事项列表,展示如何查找元素、创建元素、修改内容和样式。
|// 创建一个待办事项容器 let todoContainer = document.createElement('div'); todoContainer.id = 'todoContainer'; todoContainer.style.padding = '20px'; todoContainer.style.maxWidth = '500px'; todoContainer.style.margin = '0 auto'; // 创建标题 let title = document.createElement('h2'); title.textContent = '我的待办事项';
这个综合示例展示了如何使用DOM操作来创建一个完整的交互式功能。我们创建了多个元素,设置了它们的样式,添加了事件监听器,并且实现了添加和删除功能。通过这个例子,我们可以看到DOM操作的强大之处,它让我们能够用JavaScript来构建动态的、交互式的网页内容。
|// 获取第一个段落元素 let firstP = document.querySelector('p'); // 修改文本内容和颜色 if (firstP) { firstP.textContent = '这是修改后的文本'; firstP.style.color = 'blue'; } // 创建新的段落元素 let newP = document.createElement('p'); newP.textContent = '这是新创建的段落'; newP.style.color = 'green'
|// 创建新的div元素 let newDiv = document.createElement('div'); // 设置class和id newDiv.className = 'my-card'; newDiv.id = 'card-1'; // 或者使用classList添加类 newDiv.classList.add('my-card', 'highlight'); // 设置文本内容 newDiv.textContent = '这是新创建的卡片'; // 设置样式 newDiv.style.padding = '20px';
|// 查找所有带有'highlight'类的元素 let highlightElements = document.querySelectorAll('.highlight'); // 遍历并修改样式 highlightElements.forEach(function(element) { element.style.backgroundColor = 'yellow'; element.style.padding = '10px'; element.style.border = '2px solid orange'; }); // 也可以查找第一个匹配的元素 let firstHighlight = document.querySelector