Node

Baseline 广泛可用 *

此特性已相当成熟,可在许多设备和浏览器版本上使用。自 ⁨2015 年 7 月⁩以来,各浏览器均已提供此特性。

* 此特性的某些部分可能存在不同级别的支持。

DOM 中的 Node 接口是一个抽象基类,许多其他 DOM API 对象都基于它,从而使这些对象类型可以以相似的方式使用,甚至经常可以互换使用。作为一个抽象类,不存在纯粹的 Node 对象。所有实现 Node 功能的对象都基于它的一个子类。最值得注意的有 DocumentElementDocumentFragment

此外,每种 DOM 节点都由一个基于 Node 的接口表示。这些接口包括 AttrCharacterDataTextCommentCDATASectionProcessingInstruction 都基于它),以及 DocumentType

在某些情况下,基础 Node 接口的特定功能可能不适用于其子接口之一;在这种情况下,继承的节点可能会根据情况返回 null 或抛出异常。例如,尝试向不能有子节点的节点类型添加子节点将抛出异常。

EventTarget Node

实例属性

除了下面的属性,Node 还继承了其父类 EventTarget 的属性。.

Node.baseURI 只读

返回一个字符串,表示包含该 Node 的文档的基 URL。

Node.childNodes 只读

返回一个实时的 NodeList,其中包含该节点的所有子节点(包括元素、文本和注释)。NodeList 是实时的,意味着如果节点的子节点发生更改,NodeList 对象会自动更新。

Node.firstChild 只读

返回一个 Node,表示该节点的第一个直接子节点,如果该节点没有子节点,则返回 null

Node.isConnected 只读

一个布尔值,指示该节点是否已连接(直接或间接)到上下文对象,例如,在普通 DOM 中是 Document 对象,在 Shadow DOM 中是 ShadowRoot

Node.lastChild 只读

返回一个 Node,表示该节点的最后一个直接子节点,如果该节点没有子节点,则返回 null

Node.nextSibling 只读

返回一个 Node,表示树中的下一个节点,如果没有这样的节点,则返回 null

Node.nodeName 只读

返回一个字符串,包含 Node 的名称。名称的结构会因节点类型而异。例如,HTMLElement 将包含相应标签的名称,如 HTMLAudioElement 的 `'AUDIO'`;Text 节点将具有 `'#text'` 字符串;Document 节点将具有 `'#document'` 字符串。

Node.nodeType 只读

返回一个 unsigned short,表示节点的类型。可能的值为:

名称
ELEMENT_NODE 1
ATTRIBUTE_NODE 2
TEXT_NODE 3
CDATA_SECTION_NODE 4
PROCESSING_INSTRUCTION_NODE 7
COMMENT_NODE 8
DOCUMENT_NODE 9
DOCUMENT_TYPE_NODE 10
DOCUMENT_FRAGMENT_NODE 11
Node.nodeValue

获取/设置当前节点的值。

Node.ownerDocument 只读

返回此节点所属的 Document。如果节点本身是文档,则返回 null

Node.parentNode 只读

返回此节点的父节点 Node。如果没有这样的节点——例如,如果此节点是树的顶部,或者它不参与树——则此属性返回 null

Node.parentElement 只读

返回此节点的父节点 Element。如果节点没有父节点,或者父节点不是 Element,则此属性返回 null

Node.previousSibling 只读

返回一个 Node,表示树中的上一个节点,如果没有这样的节点,则返回 null

Node.textContent

获取/设置元素及其所有后代的文本内容。

实例方法

除了下面的方法,Node 还继承了其父类 EventTarget 的方法。

Node.appendChild()

将指定的 childNode 参数添加为当前节点的最后一个子节点。如果参数引用了 DOM 树中的现有节点,则该节点将被从其当前位置分离,并附加到新位置。

Node.cloneNode()

克隆一个 Node,可选地克隆其所有内容。默认情况下,它会克隆节点的内容。

Node.compareDocumentPosition()

比较当前节点与任何其他文档中的另一个节点的位置。

Node.contains()

返回一个布尔值,指示一个节点是否是调用节点的后代。

Node.getRootNode()

返回上下文对象的根,如果可用,则可选地包括 shadow root。

Node.hasChildNodes()

返回一个布尔值,指示该元素是否具有任何子节点。

Node.insertBefore()

将一个 Node 插入到指定父节点下的引用节点之前。

Node.isDefaultNamespace()

接受一个命名空间 URI 作为参数,并返回一个布尔值,如果命名空间是给定节点上的默认命名空间,则返回 true,否则返回 false

Node.isEqualNode()

返回一个布尔值,指示两个节点是否类型相同并且所有定义数据点都匹配。

Node.isSameNode()

返回一个布尔值,指示两个节点是否相同(即,它们是否引用同一个对象)。

Node.lookupPrefix()

返回一个字符串,包含给定命名空间 URI 的前缀(如果存在),否则返回 null。当有多个可能的前缀时,结果取决于实现。

Node.lookupNamespaceURI()

接受一个前缀,并返回与该前缀在给定节点上关联的命名空间 URI(如果找到),否则返回 null。提供 null 作为前缀将返回默认命名空间。

Node.normalize()

清理此元素下的所有文本节点(合并相邻的,删除空的)。

Node.removeChild()

从当前节点中移除一个子节点,该节点必须是当前节点的子节点。

Node.replaceChild()

用参数中给出的第二个 Node 替换当前节点的一个子 Node

事件

selectstart

当用户在此节点上开始新的选择时触发。

示例

移除节点内的所有嵌套子节点。

此函数逐个移除元素的最先子节点,直到没有剩余为止。

js
function removeAllChildren(element) {
  while (element.firstChild) {
    element.removeChild(element.firstChild);
  }
}

使用此函数是一个单一调用。这里我们清空文档的 body。

js
removeAllChildren(document.body);

一个替代方法是将 textContent 设置为空字符串:document.body.textContent = ""

递归遍历子节点。

以下函数递归地为根节点包含的每个节点(包括根节点本身)调用回调函数。

js
function eachNode(rootNode, callback) {
  if (!callback) {
    const nodes = [];
    eachNode(rootNode, (node) => {
      nodes.push(node);
    });
    return nodes;
  }

  if (callback(rootNode) === false) {
    return false;
  }

  if (rootNode.hasChildNodes()) {
    for (const node of rootNode.childNodes) {
      if (eachNode(node, callback) === false) {
        return;
      }
    }
  }
}

该函数递归地为 rootNode 的每个后代节点(包括根节点本身)调用一个函数。

如果省略 callback,则该函数返回一个 Array,其中包含 rootNode 和其中包含的所有节点。

如果提供了 callback,并且在调用时返回 false,则当前递归级别将被中止,函数将恢复执行到最后一个父级的级别。这可以用于在找到节点时中止循环(例如,搜索包含特定字符串的文本节点)。

该函数有两个参数:

rootNode

将递归遍历其后代的 Node 对象。

callback 可选

一个可选的回调 函数,它接收一个 Node 作为其唯一参数。如果省略,eachNode 将返回一个包含 rootNode 中所有节点(包括根节点本身)的 Array

以下演示了 eachNode() 函数在现实世界中的使用:在网页上搜索文本。

我们使用一个名为 grep 的包装函数来执行搜索。

js
function grep(parentNode, pattern) {
  let matches = [];
  let endScan = false;

  eachNode(parentNode, (node) => {
    if (endScan) {
      return false;
    }

    // Ignore anything which isn't a text node
    if (node.nodeType !== Node.TEXT_NODE) {
      return;
    }

    if (typeof pattern === "string" && node.textContent.includes(pattern)) {
      matches.push(node);
    } else if (pattern.test(node.textContent)) {
      if (!pattern.global) {
        endScan = true;
        matches = node;
      } else {
        matches.push(node);
      }
    }
  });

  return matches;
}

规范

规范
DOM
# interface-node

浏览器兼容性