# DOM 规范
# DOM2 和 DOM3
DOM1( DOM Level 1)主要定义了 HTML 和 XML 文档的底层结构。
DOM2( DOM Level 2)和 DOM3( DOM Level 3)在这些结构之上加入更多交互能力,提供了更高级的 XML 特性。
实际上, DOM2和 DOM3 是按照模块化的思路来制定标准的,每个模块之间有一定关联,但分别针对某个 DOM 子集。这些模式如下所示。
- DOM Core
- DOM Views
- DOM Events
- DOM Style
- DOM Travesal and Range
- DOM HTML
- DOM Mutation Observers
- Xpath
- Load and Save
# DOM 的演进
DOM2 和 DOM3 Core 模块的目标是扩展 DOM API,满足 XML 的所有需求并提供更好的错误处理和特性检测。
DOM2 Core 没有新增任何类型,仅仅在 DOM1 Core 基础上增加了一些方法和属性。
DOM3 Core 则除了增强原有类型,也新增了一些新类型。
# 样式
任何时候,只要获得了有效 DOM 元素的引用,就可以通过 JavaScript 来设置样式。来看下面的例子:
let myDiv = document.getElementById("myDiv");
// 设置背景颜色
myDiv.style.backgroundColor = "red";
// 修改大小
myDiv.style.width = "100px";
myDiv.style.height = "200px";
// 设置边框
myDiv.style.border = "1px solid black";
DOM2 Style在 document.defaultView 上增加了 getComputedStyle()
方法。这个方法接收两个参数:要取得计算样式的元素和伪元素字符串(如":after")。
getComputedStyle()
方法返回一个 CSSStyleDeclaration
对象(与 style 属性的类型一样),包含元素的计算样式。
let myDiv = document.getElementById("myDiv");
let computedStyle = document.defaultView.getComputedStyle(myDiv, null);
console.log(computedStyle.backgroundColor); // "red"
console.log(computedStyle.width); // "100px"
console.log(computedStyle.height); // "200px"
console.log(computedStyle.border); // "1px solid black"(在某些浏览器中)
# 遍历
遍历一颗 DOM 树,我们可以通过编写 BFS 或 DFS 算法来实现。 不过现在 DOM 已经为我们提供了一个遍历的工具。
DOM2 Traversal and Range 模块定义了两个类型用于辅助顺序遍历 DOM 结构。
这两个类型—— NodeIterator
和 TreeWalker
——从某个起点开始执行对 DOM 结构的深度优先遍历。
以下代码定义了只接收<p>
元素的节点过滤器对象:
let filter = {
acceptNode(node) {
return node.tagName.toLowerCase() == "p" ?
NodeFilter.FILTER_ACCEPT :
NodeFilter.FILTER_SKIP;
}
};
let iterator = document.createNodeIterator(
root,
NodeFilter.SHOW_ELEMENT,
filter,
false
);
TreeWalker 是 NodeIterator 的高级版。除了包含同样的 nextNode()、 previousNode()方法,TreeWalker 还添加了如下在 DOM 结构中向不同方向遍历的方法。
- parentNode()
- firstChild()
- lastChild()
- nextChild()
- previousSibling()
# 范围
为了支持对页面更细致的控制, DOM2 Traversal and Range 模块定义了范围接口。范围可用于在文档中选择内容,而不用考虑节点之间的界限。(选择在后台发生,用户是看不到的。)范围在常规 DOM操作的粒度不够时可以发挥作用。
DOM2 在 Document 类型上定义了一个 createRange()方法,暴露在 document 对象上。使用这个方法可以创建一个 DOM 范围对象,如下所示:
let range = document.createRange();
- 简单选择
通过范围选择文档中某个部分最简单的方式,就是使用 selectNode()或 selectNodeContents()方法。这两个方法都接收一个节点作为参数,并将该节点的信息添加到调用它的范围。
- selectNode() 方法选择整个节点,包括其后代节点
- selectNodeContents() 只选择节点的后代
let range1 = document.createRange();
let range2 = document.createRange();
p1 = document.getElementById("p1");
range1.selectNode(p1);
range2.selectNodeContents(p1);
- 复杂选择
要创建复杂的范围,需要使用 setStart()和 setEnd()方法。这两个方法都接收两个参数:参照节点和偏移量。
- 对 setStart()来说,参照节点会成为 startContainer,而偏移量会赋值给 startOffset。
- 对 setEnd()而言,参照节点会成为 endContainer,而偏移量会赋值给 endOffset。
TIP
TODO 待续,这一块主要对应富文本相关知识