DOM 精通了?請問 Node 和 Element 有何區別?

Node和Element的區別

前言

相信我們很多同學都經常會使用到 Node(節點)和 Element(節點)的概念,那麼這兩者到底有何區別,不知道有多少人能夠答得上來這個問題?

今天,我在這裏嘗試着解釋一下 Node 和 Element 的區別。

準備工作

在正式開始介紹 Node 和 Element 區別之前,我們先準備以下代碼:

<div id="parent">
    This is parent content.
    <div id="child1">This is child1.</div>
    <div id="child2">This is child2.</div>
</div>

下面的絕大多數現象和結論都將藉助這段代碼的結構來進行展示說明。

getElementById 獲取到的到底是什麼?

document.getElementById() 方法應該是我們最常使用的接口之一,那麼它的返回值到底是 Node 還是 Element?

我們使用以下代碼驗證一下:

let parentEle = document.getElementById('parent');
parentEle instanceof Node
// true
parentEle instanceof Element
// true
parentEle instanceof HTMLElement
// true

可以看到,document.getElementById() 獲取到的結果既是 Node 也是 Element。

Node、ELement 和 HTMLElement 有什麼關係?

上面的代碼中爲什麼要用 Node、Element 和 HTMLElement 來做類型判斷?它們之間到底有何關係?

看代碼:

let parentEle = document.getElementById('parent');

parentEle.__proto__
// HTMLDivElement {…}

parentEle.__proto__.__proto__
// HTMLElement {…}

parentEle.__proto__.__proto__.__proto__
// Element {…}

parentEle.__proto__.__proto__.__proto__.__proto__
// Node {…}

parentEle.__proto__.__proto__.__proto__.__proto__.__proto__
// EventTarget {…}

parentEle.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__
// {constructor: ƒ, …}

parentEle.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__
// null

對於以上輸出結果,我們可以用一張圖更直觀地表示它們之間的關係:

各層級關係

這也就解釋了爲什麼 getElementById 獲取到的既是 Node 也是 Element,因爲 Element 繼承於 Node

從而也可以得出一個結論:Element 一定是 Node,但 Node 不一定是 Element

所以:Element 可以使用 Node 的所有方法

更直白地觀察 Node 和 Element

雖然得出了上面的結論,也清楚了 Node 和 Element 的關係,但是那只是理論,我們還需要更直白的結果來強化對理論的認知。

image-20220220192550930

NodeList 內容:

  • [0] "\n This is parent content."
  • [2] "\n "
  • [4] "\n "

Element.children 獲取到的只是父元素點下的所有 div,而 Element.childNodes 獲取到的卻是父節點下的所有節點(包含文本內容、元素)。

單個 Node 的界限在哪裏?

從上面例子的 NodeList 內容中,換行符 \n 被當成一個單獨的 Node,由此產生了一個新的疑惑:單個 Node 產生的界限在哪裏?

我們將用到的 HTML 代碼去掉格式化、合併爲一行,修改如下:

<div id="parent">This is parent content.<div id="child1">This is child1.</div><div id="child2">This is child2.</div></div>

輸出結果:

image-20220220194417512

NodeList 中的沒有換行符了,原來之前例子中 NodeList 裏的換行符是因爲原始代碼中, HTML 標籤與標籤、內容與標籤之間換行而產生的

現在就可以回答單個 Node 的界限在哪裏了,兩個方面:

  • 單個的 HTML 標籤算是一個單獨的 Node;
  • 針對非 HTML標籤(比如文本、空格等),從一個 HTML 標籤的起始標籤開始,到碰到的第一個 HTML 標籤爲止,如果中間有內容(文本、空格等),那這部分內容算是一個 Node。

再進一步

因爲上面的例子中使用的都是塊級元素,那如果使用行內元素會怎樣?

試驗一:

<div id="parent">This is parent content.<span>This is a span.</span><div id="child1">This is child1.</div><div id="child2">This is child2.</div></div>

image-20220220195932524

試驗二:

<body>
    <div id="parent">This is parent content\n.
        <span>This is a span.</span>
        <div id="child1">This is child1.</div><div id="child2">This is child2.</div>
    </div>
</body>

image-20220220200356694

可以看到,即使使用了 span 元素,最後的結果也是符合上面得出的單個 Node 界限結論的。

擴展

從以上這麼多例子中,我們可以再擴展總結一下:

  • HTML 中的換行只能使用 </br> 標籤,\n 會被直接解析成字符串;
  • HTML 代碼中,標籤與文本之間、標籤和標籤之間的換行都會被如實記錄,反映到獲取結果上就是 \n
  • HTML 代碼中,標籤與標籤、文本與文本、文本與標籤之間的空格不被如實記錄;
  • node.data 內容中 \n 後面的空格字符數和實際代碼中格式化空格配置數有關,其實也就是“空格會被如實記錄”。

總結

以上通過幾個例子說明了一下 Node 和 Element 之間的區別,主要結論總結起來就是:

  • document.getElementById() 獲取到的結果既是 Node 也是 Element。
  • Element 一定是 Node,但 Node 不一定是 Element,也可能是文本、空格和換行符。
  • NodeList 裏的換行符是因爲原始代碼中, HTML 標籤與標籤、內容與標籤之間換行而產生的。
  • 單個的 HTML 標籤算是一個單獨的 Node。
  • 針對非 HTML標籤(比如文本、空格等),從一個 HTML 標籤的起始標籤開始,到碰到的第一個 HTML 標籤爲止,如果中間由內容(文本、空格等),那這部分內容算是一個 Node。

~

~ 本文完,感謝閱讀!

~

學習有趣的知識,結識有趣的朋友,塑造有趣的靈魂!

大家好,我是〖編程三昧〗的作者 隱逸王,我的公衆號是『編程三昧』,歡迎關注,希望大家多多指教!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章