DOM1、DOM2、 DOM3。 你真的明白DOM吗?

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 文档中的元素。除此之外,还有许多其他接口,如 AttrNodeListNamedNodeMap 等。

下面简单的 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,我们可以构建出各种复杂的文本编辑器和富文本应用程序。

DOM1、DOM2、 DOM3。 你真的明白DOM吗?
DOM1、DOM2、 DOM3。 你真的明白DOM吗?
DOM1、DOM2、 DOM3。 你真的明白DOM吗?

原文链接:https://juejin.cn/post/7238446447175155767 作者:Web大鹅只会叫

(0)
上一篇 2023年5月30日 上午10:57
下一篇 2023年5月30日 上午11:09

相关推荐

发表回复

登录后才能评论