js樹形結構向上查詢父節點,easyui的tree獲取父節點_通過DOM API 查找節點

 2023-12-25 阅读 29 评论 0

摘要:在上一篇的分享當中,我們簡單介紹了BOM 與DOM,也了解到JavaScript 是怎么通過它們提供的方法來與瀏覽器進行溝通。當一個網頁被載入到瀏覽器時,瀏覽器會首先分析這個HTML 文檔,然后會依照這份HTML 的內容解析成DOM (Document Object Model,

2479c21bcd119768d49210126467ec2e.png

在上一篇的分享當中,我們簡單介紹了BOM 與DOM,也了解到JavaScript 是怎么通過它們提供的方法來與瀏覽器進行溝通。

當一個網頁被載入到瀏覽器時,瀏覽器會首先分析這個HTML 文檔,然后會依照這份HTML 的內容解析成DOM (Document Object Model,即文件對象模型)。

而DOM 是W3C 制定的一個規范,它是獨立于平臺與語言的標準。換言之,只要遵守這樣的規范,不管是什么平臺或者是什么語言開發,都可以通過DOM 提供的API 來操作DOM 的內容、結構與樣式。

所以說,DOM 是網頁的根本,懂得控制DOM就可以控制整個網頁,做出良好的互動體驗

js樹形結構向上查詢父節點、那么在今天的分享中,我們就繼續來介紹DOM API 查找節點的方法吧。

前言:<script>標簽放哪里有區別嗎?

針對<script>標簽放哪里,這個題目其實沒有標準答案,一般你會看到有兩種版本:

  • 放在<head> ... </head>之間
  • 放在</body>之前

還有人會說為什么放在<head> ... </head>里面的JavaScript沒有作用?我覺得這說的有出入,這里我們簡單來講一下問題所在。

那么我們來試試上一篇介紹過的,先以document.querySelector取得id="hello"的節點,然后通過textContent來修改內容。

先來試試把<script>標簽放在</body>之前。在jsbin里面馬上執行看看,看起來似乎很ok呢!

511b330b527ccba533c3af86bf470351.png

easytree?接著,我們試著把<script>標簽移到<head> ... </head>之間:

84ae220ec62c046d3162c8dcd5e41aef.png

咦?怎么什么都沒有呢?而且也沒有錯誤信息,JavaScript真的如大家說的一樣,很垃圾嗎?

997e95554fef358e2365331804dbbff5.png

冷靜一下,容我解釋一下。

前面說過,當一個網頁被載入到瀏覽器時,瀏覽器會先分析這個HTML 文檔,由上而下依序來讀取解析:

父節點什么意思?

33bd2fe31c0ad52f887262c8a299efce.png

所以上面jsbin例子中,當瀏覽器在<head> ... </head>之間遇到<script>標簽時,就會暫停解析網頁,并且立即執行<script>里的內容,直到script執行完畢后再繼續解析網頁。

<head> ... </head>里的<script>想要嘗試去尋找<div id="hello">這個標簽,但因為還沒解析到網頁本體,所以也無從取得。

不是瀏覽器壞掉,也不是JavaScript太渣,而是因為我們不理解瀏覽器執行的原理所造成的誤會

這里是瀏覽器加載一個有 <script> 標簽的網站所發生的事情:

  1. 拉取 HTML 頁面
  2. 開始解析 HTML
  3. 解析到 <script> 標簽之后準備獲取 script 文件.
  4. 瀏覽器獲取script文件。同時,html 解析中斷并且阻斷頁面上其他html的解析。
  5. 一段時間后,script下載完成并且執行
  6. 繼續解析HTML文檔的其他部分(解析script之后的html代碼)

第4步導致了很不好的用戶體驗,直到script文件全部下載完成之前HTML都不能得到解析。

treegrid組件、那么,當我們把<script>標簽放在</body>結束之前,由于DOM已經解析完成,所以document.querySelector就可以順利取得id="hello"的節點,并且把'HELLO'的字串放在網頁里啦!

這樣說起來,<script>標簽是不是就不適合放在<head> ... </head>之間呢?

也不能這么說,這點認真要講的話之后或許可以用一整篇來說明這個。

DOM 節點的選取

fb8cf2eb3b99ddf34ecf541d21d660ca.png

上一篇文章說過,document對象是DOM tree的根節點,所以當我們要存取HTML時,都從document對象開始。而DOM的節點類型除了HTML元素節點(element nodes)外,還有文字節點(text nodes)、注釋節點(comment nodes)等。

而常見的DOM 選取方法有下列這些:

// 根據傳入的值,找到 DOM 中 id 為 'xxx' 的元素。
document.getElementById('xxx');// 針對給定的 tag 名稱,返回所有符合條件的 NodeList 對象(節點的集合)
document.getElementsByTagName('xxx');// 針對給定的 class 名稱,返回所有符合條件的節點集合
document.getElementsByClassName('xxx');// 針對給定的 Selector 條件,返回第一個 或 所有符合條件的節點集合
document.querySelector('xxx'); 
document.querySelectorAll('xxx');

DOM 節點的類型

easyui過時了嗎?DOM 常用的節點類型有下面幾種:

67fbf7fa3ab86a788ea3df761eda58fb.png

可以通過節點類型常數或是對應數值來判斷:

document.nodeType === Node.DOCUMENT_NODE;   //true
document.nodeType === 9;   //true

其他不常用或是已經廢棄的部分可以參考:MDN Node.nodeType一節。

DOM 節點間的查找遍歷(Traversing)

由于DOM 節點有分層的概念,于是節點與節點之間的關系,我們大致上可以分成以下兩種:

  • 父子關系
    除了document之外,每一個節點都會有個上層的節點,我們通常稱之為「父節點」 (Parent node),而相對地,從屬于自己下層的節點,就會稱為「子節點」 (Child node)。
  • 兄弟關系:有同一個「父節點」的節點,那么他們彼此之間就是「兄弟節點」(Siblings node)。

而隔層的節點基本上沒有直接關系。

treegrid取消行編輯?

fc589c98dc4930e086933ca3dc0bf0e9.png

上圖中水平方向的鄰層節點為父子關系,垂直方向的同層節點為兄弟關系。

Node.childNodes

所有的DOM節點對象都有childNodes屬性,且此種屬性無法修改。

我們可以通過Node.hasChildNodes()來檢查某個DOM節點是否有子節點。

var node = document.querySelector('#hello');// 如果 node 內有子元素
if( node.hasChildNodes() ) {// 可以通過 node.childNodes[n] (n 為數字索引) 取得對應的節點// 注意,NodeList 對象內容為即時更新的集合for (var i = 0; i < node.childNodes[i].length; i++) {// ...     }; 
}

Node.childNodes返回的可能會有這幾種:

  • HTML 元素節點(element nodes)
  • 文字節點(text nodes),包含空格
  • 注釋節點(comment nodes)

java easyui動態菜單。Node.firstChild

Node.firstChild可以取得Node節點的第一個子節點,如果沒有子節點則返回null

要注意的是,子節點包括空白節點,如下面例子:

<p><span>span 1</span><span>span 2</span><span>span 3</span>
</p><script>var p = document.querySelector('p');    // tagName 屬性可以取得 node 的標簽名稱console.log(p.firstChild.tagName);      // undefined
</script>

因為取得的是<p>與第一個<span>中間的換行字元,所以p.firstChild.tagName會得到undefined。所以改成這樣:

<p><span>span 1</span><span>span 2</span><span>span 3</span></p><script>var p = document.querySelector('p');    // tagName 屬性可以取得 node 的標簽名稱console.log(p.firstChild.tagName);      // "SPAN"
</script>

把中間的換行與空白移除,就會得到預期中的"SPAN"了。

Node.lastChild

vuetreeselect。Node.lastChild可以取得Node節點的最后一個子節點,如果沒有子節點則返回null

Node.firstChild一樣的是,子節點也包括空白節點,所以像這樣:

<p><span>span 1</span><span>span 2</span><span>span 3</span>
</p><script>var p = document.querySelector('p');    // textContent 屬性可以取得節點內的文字內容console.log(p.lastChild.textContent);      // "" (換行字元)
</script>

得到的會是一個換行字元的空字符串。

移除節點之間多余的空白后:

<p><span>span 1</span><span>span 2</span><span>span 3</span></p><script>var p = document.querySelector('p');    // textContent 屬性可以取得節點內的文字內容console.log(p.lastChild.textContent);      // "span 3"
</script>

輸出的就會是正確的"span 3" 啦。

Node.parentNode

easyui項目實戰。那么相較于Child系列,parentNode就單純一些。

通過Node.parentNode可以用來取得父元素,返回值可能會是一個元素節點(Element node)、根節點(Document node)或DocumentFragment節點。

<p><span>span 1</span><span>span 2</span><span>span 3</span></p><script>var el = document.querySelector('span');   console.log( el.parentNode.nodeName );    // "P"
</script>

Node.previousSibling

看完了DOM父與子之后,接著來看看兄弟節點。

通過Node.previousSibling可以取得同層之間的前一個節點,如果node已經是第一個節點且前面無節點,則返回null

<p><span>span 1</span><span>span 2</span><span>span 3</span></p><script>var el = document.querySelector('span');   console.log( el.previousSibling );    // null// document.querySelectorAll 會取得所有符合條件的集合,// 而 document.querySelectorAll('span')[2] 指的是「第三個」符合條件的元素。var el2 = document.querySelectorAll('span')[2];   console.log( el2.previousSibling.textContent );    // "span 2"
</script>

Node.nextSibling

Node.previousSibling類似,通過Node.nextSibling可以取得同層之間的下一個節點,如果node已經是最后一個節點,則返回null

<p><span>span 1</span><span>span 2</span><span>span 3</span></p><script>// document.querySelector 會取得第一個符合條件的元素var el = document.querySelector('span');console.log( el.nextSibling.textContent );    // "span 2"
</script>

document.getElementsBy**與document.querySelector/ document.querySelectorAll的差異

今天分享了很多關于DOM的選取以及查找遍歷的方式,其中,像是document.getElementById以及document.querySelector因為取得的一定只會有一個元素/節點,所以不會有index與length屬性。

document.getElementsBy**(注意,這里有個s)以及document.querySelectorAll則分別返回HTMLCollection與NodeList。

這兩者其實是有點差別的,HTMLCollection只收集HTML element 節點,而NodeList除了HTML element 節點,也包含文字節點、屬性節點等。當然兩者也有類似的地方,雖然不能使用數組的method,但這兩種都可以用數組索引的方式來存取內容,也就是偽數組。

另一個需要注意的地方是,HTMLCollection/NodeList在大部分情況下是即時更新的,但通過document.querySelector/document.querySelectorAll取得的NodeList是靜態的。

啥意思呢?舉個例子:

<div id="outer"><div id="inner">inner</div>
</div><script>// <div id="outer">var outerDiv = document.getElementById('outer');    // 所有的 <div> 標簽var allDivs = document.getElementsByTagName('div');    console.log(allDivs.length);    // 2// 清空 <div id="outer"> 下的節點   outerDiv.innerHTML = '';    // 因為清空了<div id="outer"> 下的節點,所以只剩下 outerconsole.log(allDivs.length);    // 1
</script>

如果改成document.querySelector的寫法:

<div id="outer"><div id="inner">inner</div>
</div><script>// <div id="outer">var outerDiv = document.getElementById('outer');    // 所有的 <div> 標簽var allDivs = document.querySelectorAll('div');    console.log(allDivs.length);    // 2// 清空 <div id="outer"> 下的節點   outerDiv.innerHTML = '';    // document.querySelector 返回的是靜態的 NodeList,不受 outerDiv 更新影響console.log(allDivs.length);    // 2
</script>

那么以上就是今天所要介紹的內容啦。

在后續的文章會再繼續說明DOM API新增/刪除/修改節點的部分,歡迎持續關注。

如果覺得文章對你有些許幫助,歡迎在我的GitHub博客點贊和關注,感激不盡!

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/1/194646.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息