浏览器Node相关API
DOM1 描述了名为 Node
的接口,这个接口是所有 DOM 节点类型都必须实现的。Node
接口在 JavaScript 中被实现为 Node
类型,在除 IE 之外的所有浏览器中都可以直接访问这个类型。在 JavaScript 中,所有节点类型都继承 Node
类型,因此所有类型都共享相同的基本属性和方法。
1. nodeType 节点类型
每个节点都有 nodeType
属性,表示该节点的类型。节点类型由定义在 Node
类型上的 12 个数值常量表示:
常量 | 值 | 含义 |
---|---|---|
Node.ELEMENT_NODE | 1 | 元素节点,例如 <p> 和 <div> |
Node.ATTRIBUTE_NODE | 2 | 元素的属性 |
Node.TEXT_NODE | 3 | 元素的文本内容或属性 |
Node.CDATA_SECTION_NODE | 4 | 文档的 CDATA 部分 |
Node.ENTITY_REFERENCE_NODE | 5 | XML 实体引用节点 |
Node.ENTITY_NODE | 6 | XML <!ENTITY ...> 节点 |
Node.PROCESSING_INSTRUCTION_NODE | 7 | 处理指令 |
Node.COMMENT_NODE | 8 | 注释节点 |
Node.DOCUMENT_NODE | 9 | Document 节点 |
Node.DOCUMENT_TYPE_NODE | 10 | 描述文档类型的 DocumentType 节点。例如 <!DOCTYPE html> 就是用于 HTML5 的。 |
Node.DOCUMENT_FRAGMENT_NODE | 11 | DocumentFragment 节点 |
Node.NOTATION_NODE | 12 | 一个 XML <!NOTATION ...> 节点 |
2. nodeName 与 nodeValue
nodeName
与 nodeValue
保存着有关节点的信息。这两个属性的值完全取决于节点类型。
3. 节点关系
3.1 parentNode 父节点
每一个节点都有 parentNode
属性,指向其 DOM 树中的父元素。如果一个节点没有父节点,则返回 null
比如获取页面中存在一个节点 cNode
,那么获取 cNode
的父节点方式如下所示。
const parentNode = cNode.parentNode;
3.2 childNodes 子节点
每个节点都有一个 childNodes
属性,其中包含一个 NodeList
的实例。NodeList
是一个类数组对象,用于存储可以按位置存取的有序节点。
虽然 NodeList
不是一个 Array
实例,但是我们可以读取它的 length
属性。当需要获取 NodeList
中某一个节点时,可以通过索引下标的方式读取,也可以使用 item
方法读取。
比如,有一个 uList
列表对象,读取它的第二个元素,如下所示
// 使用索引下标读取
const el = uList[1];
// 使用item方法读取
const el = uList.item(1);
由于 NodeList
是一个类数组,我们并不能直接使用数组的一些方法来操作它,但是可以使用 Array.prototype.slice
的方式将其转换为普通数组。
const nodeArray = Array.prototype.slice.call(node.childNodes, 0);
或者使用 ES6 中的 Array.from
。
const nodeArray = Array.from(node.childNodes);
3.3 previousSibling 上一个节点
获取同胞节点中的上一个节点。如果节点位于第一个位置,那么它的 previousSibling
是 null
。如果 childNodes
中只有一个节点,那么这个节点的 previousSibling
也是 null
。
// 获取someNode同级的上一个节点
const previousEl = someNode.previousSibling;
3.4 nextSibling 下一个节点
获取同胞节点中的下一个节点。如果节点位于最后一个位置,那么它的 nextSibling
是 null
。如果 childNodes
中只有一个节点,那么这个节点的 nextSibling
也是 null
。
// 获取someNode同级的下一个节点
const nextEl = someNode.nextSibling;
3.5 firstChild 第一个子节点
获取父节点的第一个子节点。它的值等同于 someNode.childNodes[0]
,是下标为 0
的节点的一种快速访问方式。
如果只有一个子节点,则 firstChild
等于 lastChild
。如果没有子节点,则 firstChild
和 lastChild
都是 null
。
// 获取第一个子节点
const firstEl = someNode.childNodes.firstChild;
const firstEl2 = someNode.childNodes[0];
console.log(firstEl === firstEl2); // true
3.6 lastChild 最后一个子节点
获取父节点的最后一个子节点。它的值等同于 someNode.childNodes[someNode.childNodes.lenght - 1]
,是下标为 someNode.childNodes.lenght - 1
的节点的一种快速访问方式。
如果只有一个子节点,则 firstChild
等于 lastChild
。如果没有子节点,则 firstChild
和 lastChild
都是 null
。
// 获取最后一个子节点
const lastEl = someNode.childNodes.lastChild;
const lastEl2 = someNode.childNodes[someNode.childNodes.length - 1];
console.log(lastEl === lastEl2); // true
3.7 hasChildNodes 是否有子节点
判断节点是否有一个或多个子节点。相比查询 childNodes
的 length
属性,这个方法更加便利。
// 判断节点是否有子节点
const isExistEl = someNode.hasChildNodes();
3.8 ownerDocument 文档指针
ownerDocument
属性是一个指向代表整个文档的文档节点的指针。所有节点都被创建它们(或自己所在)的文档所拥有,因为一个节点不可能同时存在于两个或者多个文档中。这个属性为迅速访问文档节点提供了便利,因为无需在文档结构中逐层上溯了。
4. 操纵节点
因为所有关系指针都是只读的,所以 DOM 又提供了一些操纵节点的方法。
4.1 appendChild 添加和移动节点
用于在 childNodes
列表末尾添加节点。添加新节点会更新相关的关系指针,包括父节点和之前的最后一个子节点。appendChild()
方法返回新添加的节点。
由于一个节点不会出现在文档中的两个或两个以上的位置,所以如果把文档中已经存在的节点传给 appendChild()
,则这个节点会从之前的位置被转移到新位置。
// 在文档中添加newNode节点
someNode.appendChild(newNode);
// 移动文档中的第一个节点到最后位置
someNode.appendChild(someNode.firstChild);
4.2 insertBefore 在某个节点之前添加新节点
如果想把节点放到 childNodes
中的特定位置而不是末尾,则可以使用 insertBefore()
方法。这个方法接收两个参数:要插入的节点和参照节点。它的返回值为要插入的节点。
insertBefore(要插入的节点, 参照节点)
同样的,移动节点也适用于 insertBefore
。
// 在最后一个节点的前面插入一个新节点
someNode.insertBefore(newNode, someNode.lastChild);
// 将第一个节点移动到最后一个节点之前的位置
someNode.insertBefore(someNode.firstChild, someNode.lastChild);
4.3 replaceChild 替换节点
replaceChild()
方法接收两个参数:要插入的节点和要替换的节点。要替换的节点会被返回并从文档树中完全移除,要插入的节点会取而代之。
replaceChild(要插入的节点, 要替换的节点)
// 替换第一个子节点
const firstChild = someNode.firstChild;
const replacedNode = someNode.replaceChild(newNode, firstChild);
console.log(replacedNode === firstChild); // true
4.4 removeChild 删除节点
要移除节点而不是替换节点,可以使用 removeChild()
方法。这个方法接收一个参数,即要移除的节点,被移除的节点会被返回。
// 移除最后一个节点
const lastChild = someNode.lastChild;
const el = someNode.removeChild(lastChild);
console.log(el === lastChild); // true
5. 其它方法
5.1 cloneNode
cloneNode()
方法接收一个布尔值参数,表示是否深复制。在传入 true
参数时,会进行深复制,即复制节点及其整个子 DOM 树。如果传入 false
,则只会复制调用该方法的节点。
比如存在如下 html 结构。
<ul>
<li>Lorem ipsum dolor sit.</li>
<li>Animi corporis ipsam suscipit.</li>
<li>Ipsum maiores mollitia sed.</li>
</ul>
假如 uList 为 ul 的引用,那么两种克隆方式如下。
const cloned1 = uList.cloneNode(false);
console.log(cloned1.length); // cloned1不包含ul的子节点,所以输出为0
const cloned2 = uList.cloneNode(true);
console.log(cloned3.length); // cloned2包含ul的所有子节点,所以输出为3
5.2 normalize
在节点上调用 normalize()
方法会检测这个节点的所有后代,从中搜索上述两种情形。如果发现空文本节点,则将其删除;如果两个同胞节点是相邻的,则将其合并为一个文本节点。
参考资料:Javascript 高级程序设计(第四版)
- 本博客所有文章除特别声明外,均可转载和分享,转载请注明出处!
- 本文地址:https://www.leevii.com/?p=2981