摘要:我們可以通過來檢查某個節(jié)點(diǎn)是否有子節(jié)點(diǎn)。通過可以用來取得父元素,返回值可能會是一個元素節(jié)點(diǎn)根節(jié)點(diǎn)或節(jié)點(diǎn)。與類似,通過可以取得同層之間的下一個節(jié)點(diǎn),如果已經(jīng)是最后一個節(jié)點(diǎn),則返回。
在上一篇的分享當(dāng)中,我們簡單介紹了BOM 與DOM,也了解到JavaScript 是怎么通過它們提供的方法來與瀏覽器進(jìn)行溝通。
當(dāng)一個網(wǎng)頁被載入到瀏覽器時,瀏覽器會首先分析這個HTML 文檔,然后會依照這份HTML 的內(nèi)容解析成DOM (Document Object Model,即文件對象模型)。
而DOM 是W3C 制定的一個規(guī)范,它是獨(dú)立于平臺與語言的標(biāo)準(zhǔn)。換言之,只要遵守這樣的規(guī)范,不管是什么平臺或者是什么語言開發(fā),都可以通過DOM 提供的API 來操作DOM 的內(nèi)容、結(jié)構(gòu)與樣式。
所以說,DOM 是網(wǎng)頁的根本,懂得控制DOM就可以控制整個網(wǎng)頁,做出良好的互動體驗。
那么在今天的分享中,我們就繼續(xù)來介紹DOM API 查找節(jié)點(diǎn)的方法吧。
前言:script標(biāo)簽放哪里有區(qū)別嗎?針對
接著,我們試著把
咦?怎么什么都沒有呢?而且也沒有錯誤信息,JavaScript真的如大家說的一樣,很垃圾嗎?
冷靜一下,容我解釋一下。
前面說過,當(dāng)一個網(wǎng)頁被載入到瀏覽器時,瀏覽器會先分析這個HTML 文檔,由上而下依序來讀取解析:
所以上面jsbin例子中,當(dāng)瀏覽器在 ... 之間遇到
上一篇文章說過,document對象是DOM tree的根節(jié)點(diǎn),所以當(dāng)我們要存取HTML時,都從document對象開始。而DOM的節(jié)點(diǎn)類型除了HTML元素節(jié)點(diǎn)(element nodes)外,還有文字節(jié)點(diǎn)(text nodes)、注釋節(jié)點(diǎn)(comment nodes)等。
而常見的DOM 選取方法有下列這些:
// 根據(jù)傳入的值,找到 DOM 中 id 為 "xxx" 的元素。
document.getElementById("xxx");
// 針對給定的 tag 名稱,返回所有符合條件的 NodeList 對象(節(jié)點(diǎn)的集合)
document.getElementsByTagName("xxx");
// 針對給定的 class 名稱,返回所有符合條件的節(jié)點(diǎn)集合
document.getElementsByClassName("xxx");
// 針對給定的 Selector 條件,返回第一個 或 所有符合條件的節(jié)點(diǎn)集合
document.querySelector("xxx");
document.querySelectorAll("xxx");
DOM 節(jié)點(diǎn)的類型
DOM 常用的節(jié)點(diǎn)類型有下面幾種:
可以通過節(jié)點(diǎn)類型常數(shù)或是對應(yīng)數(shù)值來判斷:
document.nodeType === Node.DOCUMENT_NODE; //true
document.nodeType === 9; //true
其他不常用或是已經(jīng)廢棄的部分可以參考:MDN Node.nodeType一節(jié)。
DOM 節(jié)點(diǎn)間的查找遍歷(Traversing)由于DOM 節(jié)點(diǎn)有分層的概念,于是節(jié)點(diǎn)與節(jié)點(diǎn)之間的關(guān)系,我們大致上可以分成以下兩種:
父子關(guān)系:除了document之外,每一個節(jié)點(diǎn)都會有個上層的節(jié)點(diǎn),我們通常稱之為「父節(jié)點(diǎn)」 (Parent node),而相對地,從屬于自己下層的節(jié)點(diǎn),就會稱為「子節(jié)點(diǎn)」 (Child node)。
兄弟關(guān)系:有同一個「父節(jié)點(diǎn)」的節(jié)點(diǎn),那么他們彼此之間就是「兄弟節(jié)點(diǎn)」(Siblings node)。
而隔層的節(jié)點(diǎn)基本上沒有直接關(guān)系。
上圖中水平方向的鄰層節(jié)點(diǎn)為父子關(guān)系,垂直方向的同層節(jié)點(diǎn)為兄弟關(guān)系。
Node.childNodes
所有的DOM節(jié)點(diǎn)對象都有childNodes屬性,且此種屬性無法修改。
我們可以通過Node.hasChildNodes()來檢查某個DOM節(jié)點(diǎn)是否有子節(jié)點(diǎn)。
var node = document.querySelector("#hello");
// 如果 node 內(nèi)有子元素
if( node.hasChildNodes() ) {
// 可以通過 node.childNodes[n] (n 為數(shù)字索引) 取得對應(yīng)的節(jié)點(diǎn)
// 注意,NodeList 對象內(nèi)容為即時更新的集合
for (var i = 0; i < node.childNodes[i].length; i++) {
// ...
};
}
Node.childNodes返回的可能會有這幾種:
HTML 元素節(jié)點(diǎn)(element nodes)
文字節(jié)點(diǎn)(text nodes),包含空格
注釋節(jié)點(diǎn)(comment nodes)
Node.firstChild
Node.firstChild可以取得Node節(jié)點(diǎn)的第一個子節(jié)點(diǎn),如果沒有子節(jié)點(diǎn)則返回null。
要注意的是,子節(jié)點(diǎn)包括空白節(jié)點(diǎn),如下面例子:
<p>
<span>span 1span>
<span>span 2span>
<span>span 3span>
p>
<script>
var p = document.querySelector("p");
// tagName 屬性可以取得 node 的標(biāo)簽名稱
console.log(p.firstChild.tagName); // undefined
script>
因為取得的是
與第一個中間的換行字元,所以p.firstChild.tagName會得到undefined。所以改成這樣:
<p><span>span 1span><span>span 2span><span>span 3span>p>
<script>
var p = document.querySelector("p");
// tagName 屬性可以取得 node 的標(biāo)簽名稱
console.log(p.firstChild.tagName); // "SPAN"
script>
把中間的換行與空白移除,就會得到預(yù)期中的"SPAN"了。
Node.lastChild
Node.lastChild可以取得Node節(jié)點(diǎn)的最后一個子節(jié)點(diǎn),如果沒有子節(jié)點(diǎn)則返回null。
與Node.firstChild一樣的是,子節(jié)點(diǎn)也包括空白節(jié)點(diǎn),所以像這樣:
<p>
<span>span 1span>
<span>span 2span>
<span>span 3span>
p>
<script>
var p = document.querySelector("p");
// textContent 屬性可以取得節(jié)點(diǎn)內(nèi)的文字內(nèi)容
console.log(p.lastChild.textContent); // "" (換行字元)
script>
得到的會是一個換行字元的空字符串。
移除節(jié)點(diǎn)之間多余的空白后:
<p><span>span 1span><span>span 2span><span>span 3span>p>
<script>
var p = document.querySelector("p");
// textContent 屬性可以取得節(jié)點(diǎn)內(nèi)的文字內(nèi)容
console.log(p.lastChild.textContent); // "span 3"
script>
輸出的就會是正確的"span 3" 啦。
Node.parentNode
那么相較于Child系列,parentNode就單純一些。
通過Node.parentNode可以用來取得父元素,返回值可能會是一個元素節(jié)點(diǎn)(Element node)、根節(jié)點(diǎn)(Document node)或DocumentFragment節(jié)點(diǎn)。
<p><span>span 1span><span>span 2span><span>span 3span>p>
<script>
var el = document.querySelector("span");
console.log( el.parentNode.nodeName ); // "P"
script>
Node.previousSibling
看完了DOM父與子之后,接著來看看兄弟節(jié)點(diǎn)。
通過Node.previousSibling可以取得同層之間的前一個節(jié)點(diǎn),如果node已經(jīng)是第一個節(jié)點(diǎn)且前面無節(jié)點(diǎn),則返回null。
<p><span>span 1span><span>span 2span><span>span 3span>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可以取得同層之間的下一個節(jié)點(diǎn),如果node已經(jīng)是最后一個節(jié)點(diǎn),則返回null。
<p><span>span 1span><span>span 2span><span>span 3span>p>
<script>
// document.querySelector 會取得第一個符合條件的元素
var el = document.querySelector("span");
console.log( el.nextSibling.textContent ); // "span 2"
script>
document.getElementsBy*與document.querySelector/ document.querySelectorAll的差異
今天分享了很多關(guān)于DOM的選取以及查找遍歷的方式,其中,像是document.getElementById以及document.querySelector因為取得的一定只會有一個元素/節(jié)點(diǎn),所以不會有index與length屬性。
而document.getElementsBy**(注意,這里有個s)以及document.querySelectorAll則分別返回HTMLCollection與NodeList。
這兩者其實(shí)是有點(diǎn)差別的,HTMLCollection只收集HTML element 節(jié)點(diǎn),而NodeList除了HTML element 節(jié)點(diǎn),也包含文字節(jié)點(diǎn)、屬性節(jié)點(diǎn)等。當(dāng)然兩者也有類似的地方,雖然不能使用數(shù)組的method,但這兩種都可以用數(shù)組索引的方式來存取內(nèi)容,也就是偽數(shù)組。
另一個需要注意的地方是,HTMLCollection/NodeList在大部分情況下是即時更新的,但通過document.querySelector/document.querySelectorAll取得的NodeList是靜態(tài)的。
啥意思呢?舉個例子:
<div id="outer">
<div id="inner">innerdiv>
div>
<script>
//
var outerDiv = document.getElementById("outer");
// 所有的 標(biāo)簽
var allDivs = document.getElementsByTagName("div");
console.log(allDivs.length); // 2
// 清空 下的節(jié)點(diǎn)
outerDiv.innerHTML = "";
// 因為清空了 下的節(jié)點(diǎn),所以只剩下 outer
console.log(allDivs.length); // 1
script>
如果改成document.querySelector的寫法:
<div id="outer">
<div id="inner">innerdiv>
div>
<script>
//
var outerDiv = document.getElementById("outer");
// 所有的 標(biāo)簽
var allDivs = document.querySelectorAll("div");
console.log(allDivs.length); // 2
// 清空 下的節(jié)點(diǎn)
outerDiv.innerHTML = "";
// document.querySelector 返回的是靜態(tài)的 NodeList,不受 outerDiv 更新影響
console.log(allDivs.length); // 2
script>
那么以上就是今天所要介紹的內(nèi)容啦。
在后續(xù)的文章會再繼續(xù)說明DOM API新增/刪除/修改節(jié)點(diǎn)的部分,歡迎持續(xù)關(guān)注。
如果覺得文章對你有些許幫助,歡迎在我的GitHub博客點(diǎn)贊和關(guān)注,感激不盡!
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/7268.html
相關(guān)文章
-
DOM 小總結(jié)
摘要:在瀏覽器中,對象是繼承自類型的一個實(shí)例,表示整個頁面。它這種情況稱為文檔碎片,還無法顯示在瀏覽器的畫面中。創(chuàng)建一個文本節(jié)點(diǎn)并添加到新元素中的代碼如下總結(jié)文檔對象模型,是針對和文檔的一個應(yīng)用程序編程接口,描繪了一個層次化的節(jié)點(diǎn)樹。
DOM 是什么
文檔對象模型,是針對 HTML 和 XML 文檔的一個 API (應(yīng)用程序編程接口), 描繪了一個層次化的節(jié)點(diǎn)樹。
D: document
當(dāng)...
-
DOM 小總結(jié)
摘要:在瀏覽器中,對象是繼承自類型的一個實(shí)例,表示整個頁面。它這種情況稱為文檔碎片,還無法顯示在瀏覽器的畫面中。創(chuàng)建一個文本節(jié)點(diǎn)并添加到新元素中的代碼如下總結(jié)文檔對象模型,是針對和文檔的一個應(yīng)用程序編程接口,描繪了一個層次化的節(jié)點(diǎn)樹。
DOM 是什么
文檔對象模型,是針對 HTML 和 XML 文檔的一個 API (應(yīng)用程序編程接口), 描繪了一個層次化的節(jié)點(diǎn)樹。
D: document
當(dāng)...
-
重學(xué)前端學(xué)習(xí)筆記(二十三)--狹義的文檔對象DOM
摘要:事件觸發(fā)和監(jiān)聽事件相關(guān)。文檔是一個由標(biāo)簽嵌套而成的樹形結(jié)構(gòu),因此,也是使用樹形的對象模型來描述一個文檔。節(jié)點(diǎn)的寫法三是樹繼承關(guān)系的根節(jié)點(diǎn)。七表示一個上的范圍,這個范圍是以文字為最小單位的。
筆記說明
重學(xué)前端是程劭非(winter)【前手機(jī)淘寶前端負(fù)責(zé)人】在極客時間開的一個專欄,每天10分鐘,重構(gòu)你的前端知識體系,筆者主要整理學(xué)習(xí)過程的一些要點(diǎn)筆記以及感悟,完整的可以加入winter的...
-
重學(xué)前端學(xué)習(xí)筆記(二十三)--狹義的文檔對象DOM
摘要:事件觸發(fā)和監(jiān)聽事件相關(guān)。文檔是一個由標(biāo)簽嵌套而成的樹形結(jié)構(gòu),因此,也是使用樹形的對象模型來描述一個文檔。節(jié)點(diǎn)的寫法三是樹繼承關(guān)系的根節(jié)點(diǎn)。七表示一個上的范圍,這個范圍是以文字為最小單位的。
筆記說明
重學(xué)前端是程劭非(winter)【前手機(jī)淘寶前端負(fù)責(zé)人】在極客時間開的一個專欄,每天10分鐘,重構(gòu)你的前端知識體系,筆者主要整理學(xué)習(xí)過程的一些要點(diǎn)筆記以及感悟,完整的可以加入winter的...
發(fā)表評論
0條評論
shengguo
男|高級講師
TA的文章
閱讀更多
tomcat https
閱讀 1911·2021-11-25 09:43
環(huán)境影響著一個人...最高月薪20K,想成為最優(yōu)秀的人,就要向最優(yōu)秀的人學(xué)習(xí)
閱讀 1558·2021-09-02 15:21
我們來翻翻元素樣式的族譜-getComputedStyle
閱讀 3524·2019-08-30 15:52
一些問題
閱讀 1559·2019-08-30 12:48
提升網(wǎng)站頁面速度的14條最佳實(shí)踐(二)
閱讀 1374·2019-08-30 10:57
移動端H5頁面中1px邊框的幾種解決方法
閱讀 2991·2019-08-26 17:41
JS去重的幾種實(shí)現(xiàn)方法
閱讀 743·2019-08-26 11:59
for 循環(huán) var 和 let
閱讀 1427·2019-08-26 10:41
閱讀需要支付1元查看