DOM1、DOM2、 DOM3。 你真的明白DOM吗?
本文写作灵感基于第四版【JavaScript高级程序设计】,简称:红宝石书,第14章-第16章节
事前提醒:阅读本文存在不同想法时,可以在评论中表达,但请勿使用过激的措辞。
本文叙述内容:
1、什么是DOM1?
2、DOM2到DOM3的变化。
3、操作样式的DOM API。
4、你真的明白DOM遍历吗?
一、什么是DOM1?
当网页设计和开发开始流行时,HTML是逐渐变得复杂的
。为了使得以前的 HTML 页面更有效地操作
,需要一种新的编程接口
来让开发者们轻松地创建动态的 Web 页面。这就是DOM1
的出现背景。
目前官方解译:DOM1(Document Object Model Level 1) 是 W3C 定义的文档对象模型级别一规范,旨在为 HTML 和 XML 文档提供独立于平台和语言的编程接口。它定义了一组 API,用于表示和操作 HTML 和 XML 文档中的元素、属性、文本等内容,将其表示为在内存中的对象,并可以使用脚本语言来修改和处理文档。
DOM1 规范定义了一些核心接口,其中最重要的是 Document
接口和 Element
接口。Document
接口表示整个文档,而 Element
接口表示 HTML 或 XML 文档中的元素。除此之外,还有许多其他接口,如 Attr
、NodeList
、NamedNodeMap
等。
下面简单的 DOM1 代码示例:
<!DOCTYPE html>
<html>
<head>
<title>DOM1 Example</title>
</head>
<body>
<h1 id="myHeading">Hello, World!</h1>
<button onclick="changeText()">Click me</button>
<script>
function changeText() {
var heading = document.getElementById('myHeading');
heading.innerHTML = 'Hello, JavaScript!';
}
</script>
</body>
</html>
在上述代码中,我们定义了一个 HTML 文档,并在页面上添加了一个标题和一个按钮。当用户点击按钮时,调用 changeText()
函数,该函数使用 getElementById()
方法获取 id 为 “myHeading” 的元素的引用,并使用 innerHTML
属性来更改该元素的内容。
总而言之,DOM1 是为 HTML 和 XML 文档提供编程接口的第一个标准规范。它定义了一组 API,代表文档的各个部分,允许开发人员使用脚本语言轻松地创建动态 Web 页面。
二、DOM2到DOM3的变化。
DOM2 和 DOM3
是 DOM 规范的两个版本,其中 DOM2 主要增加了新的特性和方法,而 DOM3 则进一步扩展了 DOM 的能力并且加入了一些新的模块。 DOM2 和 DOM3 在 DOM1 的结构之上加入了更多的交互能力,提供了更高级的XML特性。实际上, DOM2 和 DOM3 是按照模块化的思路来指定标准的,下文中将会有体现。每一个模块之间有一定的关联,但分别针对某个 DOM 子集。这些模式如下:
* DOM Core: 在 DOM1 核心部分的基础上,为节点增加方法和属性。
* DOM Views:定义基础样式信息的不同视图。
* DOM Events:定义通过事件实现DOM文档交互。
* DOM Style:定义以编程方式访问和修改CSS样式的接口。
* DOM Traversal and Range:新增遍历DOM文档及选择文档内容的接口。
* DOM HTML:在DOM1 HTML部分的基础上,增加属性、方法和新接口。
* DOM Mutation Observers:定义基于DOM变化触发回调的接口。这个模板是DOM4级模块,用于取代Mutation Events。
下边将重点介绍 DOM2 和 DOM3 的变化以及新增的功能。
首先我们先详细了解一下什么是DOM2
DOM2 在 DOM1 的基础上添加了许多新特性和 API,包括:
* 事件处理:`addEventListener()` 和 `removeEventListener()` 方法取代了 DOM0 中的事件处理方式。
* 样式:提供了对 CSS 样式的访问和修改功能。
* 遍历器:遍历某个元素下所有的子元素
* 错误处理:增强了错误处理功能。
* 范围和选择:支持对范围和选择的操作。
下面是一些 DOM2 的代码示例:
事件处理
// 给按钮添加点击事件处理程序
var button = document.getElementById('myButton');
button.addEventListener('click', function(event) {
alert('Button clicked');
}, false);
样式
// 获取元素的样式
var element = document.getElementById('myElement');
var style = window.getComputedStyle(element, null);
var color = style.getPropertyValue('color');
遍历器
// 遍历某个元素下所有的子元素并输出其标签名
var parent = document.getElementById('parentElement');
var childNode = parent.firstChild;
while (childNode) {
if (childNode.nodeType == 1) { // 判断是否为元素节点
console.log(childNode.tagName);
}
childNode = childNode.nextSibling;
}
然后我们再了解一下什么是DOM3
DOM3 在 DOM2 的基础上进一步扩展了 DOM API,主要增加以下内容:
* XPath:用于根据 XPath 表达式选择文档的某些部分。
* Load and Save:用于将文档保存到文件或从文件加载文档。
* 校验:提供了对 XML 文档进行验证的功能。
除此之外,DOM3 还加入了很多新模块和 API:
* Core:包含了大量基本的接口和方法。
* XML:提供了对 XML 文档的支持。
* Events:定义了一组新的事件类型和事件处理程序接口。
* UI:提供了对用户界面的访问和控制。
* Style:提供了对 CSS 样式表的操作和管理。
* Load and Save:用于将文档保存到文件或从文件加载文档。
下面是一些 DOM3 的代码示例:
XPath
// 使用 XPath 搜索元素
var xpathResult = document.evaluate("//h1", document, null, XPathResult.ANY_TYPE, null);
var node = xpathResult.iterateNext();
while (node) {
console.log(node.textContent);
node = xpathResult.iterateNext();
}
Load and Save
// 加载 XML 文档并输出其内容
var xhr = new XMLHttpRequest();
xhr.open('GET', 'example.xml', true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
var xml = xhr.responseXML;
console.log(xml.documentElement.nodeName);
}
};
xhr.send();
综上所述,DOM2 和 DOM3 都为开发人员提供了更加强大的 API 和功能,以便于更好地操纵和控制文档。这些新特性可以让我们更加轻松、方便地进行 Web 开发。
三、操作样式的DOM API。
在 Web 开发中,样式表是控制页面样式的重要组成部分。除了通过操作元素的 style 属性来修改样式外,还可以使用样式表 API 来对样式进行管理。本文将通过表格形式详细介绍常用的样式表 API。
CSSStyleSheet 对象
CSSStyleSheet 是表示样式表的对象,它包括以下属性和方法:
属性/方法 | 描述 |
---|---|
cssRules |
只读,获取样式表中的所有规则(rules)。 |
ownerNode |
只读,获取当前样式表所属的节点。 |
insertRule(rule, index) |
在指定位置插入一条新规则。 |
deleteRule(index) |
删除指定位置的规则。 |
以下是一个示例代码,演示如何使用 CSSStyleSheet 对象进行样式表操作:
// 获取第一个样式表
var sheet = document.styleSheets[0];
// 获取所有规则
var rules = sheet.cssRules;
// 在索引为 0 处插入一条新规则
sheet.insertRule("body { background-color: red; }", 0);
// 删除索引为 1 的规则
sheet.deleteRule(1);
CSSRule (css规则)对象
CSSRule 是表示样式表中规则的对象,它包括以下属性和方法:
属性/方法 | 描述 |
---|---|
cssText |
可读写,获取或设置规则的文本内容。 |
parentRule |
只读,获取当前规则所属的父规则。 |
parentStyleSheet |
只读,获取当前规则所属的样式表。 |
以下是一个示例代码,演示如何使用 CSSRule 对象进行规则操作:
// 获取第一个样式表
var sheet = document.styleSheets[0];
// 获取第一条规则
var rule = sheet.cssRules[0];
// 修改规则内容
rule.cssText = "body { background-color: red; }";
// 获取规则所属的样式表
var styleSheet = rule.parentStyleSheet;
CSSStyleDeclaration 对象
CSSStyleDeclaration 是表示元素样式声明的对象,它包括以下属性和方法:
属性/方法 | 描述 |
---|---|
cssText |
可读写,获取或设置样式声明的文本内容。 |
getPropertyValue(name) |
获取指定属性名的值。 |
setProperty(name, value, priority) |
设置指定属性名的值和优先级。 |
removeProperty(name) |
移除指定属性名的值。 |
以下是一个示例代码,演示如何使用 CSSStyleDeclaration 对象进行样式声明操作:
// 获取元素的样式声明
var style = document.getElementById("myElement").style;
// 修改样式声明内容
style.cssText = "background-color: red; color: white;";
// 获取属性值
var backgroundColor = style.getPropertyValue("background-color");
// 设置属性值和优先级
style.setProperty("color", "red", "important");
// 移除属性
style.removeProperty("background-color");
四、你真的明白DOM遍历吗?
首先 DOM2 Traversal and Range 模块定义了两个类型用于辅助顺序遍历 DOM 结构。NodeTterator和TreeWalker。
这两个类型都可以从某个起点开始执行对 DOM 结构的优先遍历,并且在遍历过程中可以通过过滤器(filter)进行筛选。他们的主要区别在于遍历的范围和使用方式。
NodeIterator
NodeIterator 可以从某个节点开始沿着文档顺序遍历该节点的所有子孙节点。以下是 NodeIterator 的常用属性和方法:
root
:只读,获取或设置遍历的根节点。whatToShow
:只读,获取或设置哪些节点应该被包含在遍历中。filter
:可读写,获取或设置一个函数,用于过滤不需要的节点。nextNode()
:获取下一个节点。previousNode()
:获取前一个节点。
NodeIterator 的 遍历 API 可以用于过滤节点。以下是一些常见的 API:
遍历 API | 描述 |
---|---|
NodeFilter.SHOW_ALL |
包含所有节点类型。 |
NodeFilter.SHOW_ELEMENT |
包含元素节点。 |
NodeFilter.SHOW_TEXT |
包含文本节点。 |
NodeFilter.SHOW_COMMENT |
包含注释节点。 |
NodeFilter.SHOW_PROCESSING_INSTRUCTION |
包含处理指令节点。 |
以上 API 可以在创建 NodeIterator 或 TreeWalker 对象时使用,例如:
// 创建一个只包含元素节点的 NodeIterator 对象
var it = document.createNodeIterator(root, NodeFilter.SHOW_ELEMENT);
// 创建一个只包含注释节点的 TreeWalker 对象
var walker = document.createTreeWalker(root, NodeFilter.SHOW_COMMENT);
需要注意的是,以上 API 形成的值是一个位掩码(bitmask),可以通过按位或运算符 |
来组合不同的值。例如:
// 创建一个同时包含元素和文本节点的 NodeIterator 对象
var it = document.createNodeIterator(root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT);
总之,通过 NodeIterator 和 TreeWalker 提供的过滤器 API,我们可以非常灵活地控制 DOM 遍历的范围和行为,从而更加高效地获取和操作 DOM 节点。
以下是一个简单的示例代码,演示了如何使用 NodeIterator 遍历节点:
var root = document.getElementById('myList');
var it = document.createNodeIterator(root, NodeFilter.SHOW_ELEMENT);
while (node = it.nextNode()) {
console.log(node.nodeName);
}
上述代码中,我们创建了一个 NodeIterator 对象,并指定了遍历的根节点为 myList
元素,whatToShow 参数为 SHOW_ELEMENT,表示只包含元素节点。在遍历过程中,我们使用了 nextNode()
方法来获取下一个节点,并输出了该节点的名称。
TreeWalker
TreeWalker 可以从某个节点开始沿着文档顺序遍历该节点的所有子孙节点。与 NodeIterator 不同的是,TreeWalker 还可以指定遍历的结束节点以及是否跳过某些节点。以下是 TreeWalker 的常用属性和方法:
root
:只读,获取或设置遍历的根节点。whatToShow
:只读,获取或设置哪些节点应该被包含在遍历中。filter
:可读写,获取或设置一个函数,用于过滤不需要的节点。currentNode
:可读写,获取或设置当前节点。parentNode()
:获取当前节点的父节点。firstChild()
:获取当前节点的第一个子节点。lastChild()
:获取当前节点的最后一个子节点。nextSibling()
:获取当前节点的下一个同级节点。previousSibling()
:获取当前节点的上一个同级节点。
以下是一个简单的示例代码,演示了如何使用 TreeWalker 遍历节点:
var root = document.getElementById('myList');
var walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
while (node = walker.nextNode()) {
console.log(node.nodeName);
}
与 NodeIterator 类似,我们创建了一个 TreeWalker 对象,并指定了遍历的根节点为 myList
元素,whatToShow 参数为 SHOW_ELEMENT,表示只包含元素节点。在遍历过程中,我们使用了 nextNode()
方法来获取下一个节点,并输出了该节点的名称。
总之,NodeIterator 和 TreeWalker 可以帮助我们更加方便地进行 DOM 遍历操作,同时也具有较好的性能表现。
拓展:DOM2模块定义了范围接口。
这个范围就是用于在文档中选择内容,而不用考虑节点之间的界限。(在后台发生,用户无感)范围在常规DOM 操作中的粒度不够时可以发挥作用。
DOM范围:
当涉及到文本或节点的选择和操作时,DOM 范围 API 就非常有用了。下面我们来详细介绍 DOM 范围如何进行简单选择、复杂选择、操作范围、范围插入、范围折叠、范围比较、复制范围和清理。
简单选择
创建一个简单的文本选择非常容易,只需使用 document.createRange()
方法创建一个空范围,然后使用 range.setStart()
和 range.setEnd()
方法设置起点和终点位置。例如:
var range = document.createRange();
var startNode = document.getElementById('start');
var endNode = document.getElementById('end');
range.setStart(startNode, 1);
range.setEnd(endNode, 3);
上述代码中,我们创建了一个空范围,并设置其起点为 id
属性为 start
的元素的第二个子节点,终点为 id
属性为 end
的元素的第四个子节点。
复杂选择
除了简单选择外,DOM 范围 API 还支持更复杂的选择方式,例如:
- 选择某个元素内的所有文本。
- 选择某个元素和其子孙节点内的所有文本。
- 选择包含某个元素的整个文档片段。
- …
以下是一些示例:
var range = document.createRange();
var element = document.getElementById('myElement');
// 选择某个元素内的所有文本
range.selectNodeContents(element);
// 选择某个元素和其子孙节点内的所有文本
range.selectNode(element);
// 选择包含某个元素的整个文档片段
range.selectNode(document.documentElement);
操作范围
DOM 范围 API 提供了一些操作范围的方法,例如:
- 删除范围内的所有节点和文本。
- 在范围的起点处插入一个新的节点。
- 将范围中的所有节点和文本复制到一个新的范围中等。
以下是一些示例:
var range = document.createRange();
var startNode = document.getElementById('start');
var endNode = document.getElementById('end');
// 删除范围内的所有节点和文本
range.deleteContents();
// 在范围的起点处插入一个新的文本节点
var newNode = document.createTextNode('new text');
range.insertNode(newNode);
// 克隆并返回范围内的所有节点和文本
var clonedRange = range.cloneRange();
范围插入
将范围插入到文档中的某个位置也很容易,只需使用 range.cloneContents()
方法复制范围内的所有节点和文本,然后使用 document.createElement()
方法创建一个新的元素,并将复制的节点和文本插入到该元素中,最后将该元素插入到文档中的指定位置即可。例如:
var range = document.createRange();
var startNode = document.getElementById('start');
var endNode = document.getElementById('end');
// 选择某个元素内的所有文本
range.selectNodeContents(startNode);
// 复制范围内的节点和文本,并插入到一个新的div元素中
var div = document.createElement('div');
div.appendChild(range.cloneContents());
// 将新的div元素插入到文档中
document.body.insertBefore(div, endNode);
范围折叠
在 DOM 范围 API 中,范围折叠(collapse)是将一个范围合并为一个点的过程。范围折叠有两种方式:向起点折叠和向终点折叠。以下是一些示例:
var range = document.createRange();
// 向起点折叠
range.collapse(true);
// 向终点折叠
range.collapse(false);
范围比较
DOM 范围 API 还提供了一些方法用于比较范围,例如:
- 比较两个范围的起点位置、终点位置等。
- 判断一个范围是否包含另一个范围。
以下是一些示例:
var range1 = document.createRange();
var range2 = document.createRange();
// 比较两个范围的起点位置
range1.compareBoundaryPoints(Range.START_TO_START, range2);
// 判断一个范围是否包含另一个范围
range1.containsNode(range2.commonAncestorContainer, true);
复制范围
如果需要将一个范围复制到另一个范围中,可以使用 range.cloneRange()
方法。该方法会返回一个新的范围对象,包含与原始范围对象相同的起点和终点位置。例如:
var range1 = document.createRange();
var range2 = range1.cloneRange();
清理
最后,在使用完 DOM 范围 API 后,为避免内存泄漏,需要手动清理所有创建的范围。以下是一些示例:
var range = document.createRange();
// 使用完后清理范围
range.detach();
range = null;
DOM 范围 API 是一个非常灵活的 API,它提供了一系列方法用于选择、操作和处理文本和节点。通过巧妙地利用 DOM 范围 API,我们可以构建出各种复杂的文本编辑器和富文本应用程序。
原文链接:https://juejin.cn/post/7238446447175155767 作者:Web大鹅只会叫