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

瀏覽器相容性