文章目录
- 一、DOM 核心概念解析
- 1.1 什么是 DOM?
- 1.2 DOM 与 HTML 的关系
- 二、DOM 节点(Node)详解
- 2.1 节点类型
- 2.2 节点的基本属性
- 2.3 元素节点特有的属性和方法
- 三、DOM 选择与访问
- 3.1 传统选择方法
- 3.1.1 getElementById()
- 3.1.2 getElementsByTagName()
- 3.1.3 getElementsByClassName()
- 3.2 现代选择方法(CSS 选择器)
- 3.2.1 querySelector()
- 3.2.2 querySelectorAll()
- 3.3 特殊元素的访问
- 3.4 选择方法的对比与选择建议
一、DOM 核心概念解析
1.1 什么是 DOM?
DOM(Document Object Model)是 W3C(万维网联盟)定义的一套标准,用于表示和操作 HTML、XML 文档的结构。它将文档视为一个树形结构,每个节点都是文档的一部分,通过 JavaScript 可以对这些节点进行增删改查等操作。
简单来说,DOM 的作用是在JavaScript 和网页内容之间建立桥梁。当浏览器加载 HTML 文档时,会解析 HTML 并构建一个 DOM 树,开发者可以通过 JavaScript 访问和修改这棵树,从而实现动态更新网页内容、结构和样式的效果。
DOM 的本质:将文档转换为一个可编程的对象模型。
1.2 DOM 与 HTML 的关系
DOM 和 HTML 是两个不同的概念:
- HTML 是用于描述网页结构的标记语言(文本形式)
- DOM 是浏览器根据 HTML 解析生成的对象模型(内存中的树形结构)
举例来说,一段简单的 HTML:
<!DOCTYPEhtml><html><head><title>DOM示例</title></head><body><h1>Hello DOM !</h1></body></html>浏览器会将其解析为如下 DOM 树结构:
document └── html (根元素) ├── head │ └── title │ └── "DOM示例" (文本节点) └── body └── h1 └── "Hello DOM !" (文本节点)可以看出,DOM 树完整保留了 HTML 的层级关系,同时将每个标签、文本、属性等都转换为可操作的对象。
二、DOM 节点(Node)详解
DOM 树由各种类型的节点(Node)组成,理解节点的类型和属性是掌握 DOM 操作的基础。
2.1 节点类型
根据 W3C 标准,DOM 节点主要分为以下几种类型:
| 节点类型 | 常量 | 描述 | 示例 |
|---|---|---|---|
| 元素节点 | Node.ELEMENT_NODE | HTML 或 XML 标签 | <div>, <p>, <span> |
| 文本节点 | Node.TEXT_NODE | 元素中的文本内容 | Hello World |
| 属性节点 | Node.ATTRIBUTE_NODE | 元素的属性 | class="active",id="name" |
| 注释节点 | Node.COMMENT_NODE | 文档中的注释 | <!-- 这是注释 – > |
| 文档节点 | Node.DOCUMENT_NODE | 整个文档的根节点(document) | document对象 |
| 文档类型节点 | Node.DOCUMENT_TYPE_NODE | 文档类型声明 | <!DOCTYPE html> |
可以通过节点的nodeType属性获取节点类型,例如:
constdiv=document.querySelector('div');console.log(div.nodeType);// 1(元素节点)consttext=div.firstChild;console.log(text.nodeType);// 3(文本节点)console.log(document.nodeType);// 9(文档节点)2.2 节点的基本属性
所有节点都具有以下基本属性:
nodeName:节点的名称(只读)- 元素节点:标签名(大写)
- 文本节点:
#text - 属性节点:属性名
- 文档节点:
#document
nodeValue:节点的值- 元素节点:
null - 文本节点:文本内容
- 属性节点:属性值
- 元素节点:
nodeType:节点类型(见上文,只读)parentNode:父节点childNodes:子节点集合(类数组)firstChild:第一个子节点lastChild:最后一个子节点previousSibling:前一个兄弟节点nextSibling:后一个兄弟节点
示例代码:
<divid="demo">Hello<span>World</span></div><script>constdiv=document.getElementById('demo');console.log(div.nodeName);// "DIV"console.log(div.nodeValue);// nullconsole.log(div.nodeType);// 1console.log(div.childNodes);// NodeList(3) [text, span, text]console.log(div.firstChild.nodeName);// "#text"console.log(div.firstChild.nodeValue);// "Hello "constspan=div.querySelector('span');console.log(span.parentNode.nodeName);// "DIV"console.log(span.previousSibling.nodeType);// 3(文本节点)console.log(span.nextSibling.nodeValue);// " "</script>注意:空白字符(空格、换行等)在 DOM 中会被解析为文本节点,这也使
childNodes可能包含看似 “空” 节点的原因。
2.3 元素节点特有的属性和方法
元素节点(Element)作为最常用的节点类型,除了上述基本属性外,还有一些特有的属性和方法:
tagName:元素标签名(同nodeName,但更常用)id:元素的 id 属性className:元素的 class 属性(因为class是 JavaScript 关键字)classList:元素的类列表(提供添加、删除类的方法)attributes:元素的所有属性集合innerHTML:元素的 HTML 内容innerText/textContent:元素的文本内容style:元素的内联样式
后续章节将详细讲解这些属性的使用方法。
三、DOM 选择与访问
在操作 DOM 之前,首先需要找到要操作的元素。JavaScript 提供了多种方法来选择 DOM 节点,我们可以根据不同场景选择合适的方法。
3.1 传统选择方法
早期的 DOM 标准提供了以下选择元素的方法:
3.1.1 getElementById()
通过元素的id属性获取元素,返回单个元素(如果存在)或null。
<divid="header">这是头部</div><script>constheader=document.getElementById('header');console.log(header);// <div id="header">这是头部</div></script>特点:
- 只能通过
document调用(不能通过元素节点调用) id在文档中应该是唯一的- 区分大小写(在 HTML 中不区分,但JavaScript 中区分)
3.1.2 getElementsByTagName()
通过标签名获取元素,返回一个动态更新的 HTMLCollection 集合(类数组对象)。
<ul><li>项目1</li><li>项目2</li><li>项目3</li></ul><script>// 获取所有li元素constlis=document.getElementsByTagName('li');console.log(lis.length);// 3// 遍历集合for(leti=0;i<lis.length;i++){console.log(lis[i].innerText);}// 可以通过元素节点调用,获取其后代元素constul=document.querySelector('ul');constulLis=ul.getElementsByTagName('li');console.log(ulLis.length);// 3</script>特点:
- 可以通过
document或任意元素节点调用 - 返回的集合是 “动态的”:当 DOM 变化时,集合会自动更新
- 传入
*可以获取所有元素
3.1.3 getElementsByClassName()
通过类名获取元素,返回一个动态更新的 HTMLCollection 集合。
<divclass="box">盒子1</div><divclass="box">盒子2</div><pclass="box">段落</p><script>//单个类名查找constboxes=document.getElementsByClassName('box');console.log(boxes.length);// 3// 多个类名(空格分隔)// 查找同时包含box和special类的元素,这段代码中没有这样的元素,因此返回空集合constspecial=document.getElementsByClassName('box special');// 通过元素节点局部调用// 先通过getElementById找到 id 为container的元素(假设页面中有这个元素)// 然后只在这个元素内部查找带 box类的元素。constcontainer=document.getElementById('container');constcontainerBoxes=container.getElementsByClassName('box');</script>特点:
- 支持多个类名(同时匹配所有类名)
- 可以通过
document或任意元素节点调用 - 返回的集合是动态的
3.2 现代选择方法(CSS 选择器)
HTML5 引入了基于 CSS 选择器的选择方法,更加灵活强大,是目前开发中的首选。
3.2.1 querySelector()
根据CSS 选择器返回第一个匹配的元素,如果没有匹配项则返回null。
<divclass="container"><pclass="text">段落1</p><pclass="text">段落2</p></div><script>// 获取第一个 p元素constfirstP=document.querySelector('p');console.log(firstP.innerText);// "段落1"// 使用类选择器consttext=document.querySelector('.text');// 使用后代选择器constcontainerP=document.querySelector('.container .text');// 通过元素节点调用constcontainer=document.querySelector('.container');constcontainerP2=container.querySelector('p:last-child');console.log(containerP2.innerText);// "段落2"</script>3.2.2 querySelectorAll()
根据 CSS 选择器返回所有匹配的元素,以静态的NodeList集合形式返回。
<ul><li>项目1</li><li>项目2</li><li>项目3</li></ul><script>// 获取所有li元素constlis=document.querySelectorAll('li');console.log(lis.length);// 3// 使用伪类选择器constevenLis=document.querySelectorAll('li:nth-child(even)');// 遍历NodeList// 方法1:for循环for(leti=0;i<lis.length;i++){console.log(lis[i].innerText);}// 方法2:forEach(NodeList支持forEach方法)lis.forEach(li=>{console.log(li.innerText);});// 方法3:转换为数组后使用数组方法constlisArray=Array.from(lis);lisArray.filter(li=>li.innerText.includes('2'));</script>特点:
- 支持所有CSS 选择器语法
- 可以通过
document或任意元素节点调用 - 返回的
NodeList是静态的(DOM 变化时不会自动更新)
3.3 特殊元素的访问
除了上述选择方法,还有一些快速访问特殊元素的属性:
- 获取 html根元素
document.documentElement;// <html>- 获取 body元素
document.body;// <body>- 获取 head元素
document.head;// <head>- 获取所有表单元素
document.forms;// HTMLCollection,包含所有<form>元素- 获取所有图片元素
document.images;// HTMLCollection,包含所有<img>元素- 获取所有链接元素
document.links;// HTMLCollection,包含所有<a>和<area>元素3.4 选择方法的对比与选择建议
| 方法 | 返回值 | 动态性 | 支持的选择方式 | 兼容性 | 推荐指数 |
|---|---|---|---|---|---|
getElementById | 单个元素 | - | id | 所有浏览器 | ★★★★☆ |
getElementsByTagName | HTMLCollection | 动态 | 标签名 | 所有浏览器 | ★★★☆☆ |
getElementsByClassName | HTMLCollection | 动态 | 类名 | IE9+ | ★★★☆☆ |
querySelector | 单个元素 | - | CSS 选择器 | IE8+ | ★★★★★ |
querySelectorAll | NodeList | 静态 | CSS 选择器 | IE8+ | ★★★★★ |
选择建议:
- 简单场景下,
getElementById效率最高 - 需要复杂选择逻辑时,优先使用
querySelector和querySelectorAll - 当需要实时反映 DOM 变化时,可考虑使用
getElementsByTagName或getElementsByClassName避免在循环中频繁调用选择方法(会影响性能),应缓存选择结果