DOM系列:DOM樹和遍歷DOM

上一節(jié)焕阿,咱們整理了DOM系列中的第一篇,主要介紹瀏覽器與DOM相關(guān)的知識唇兑。從標題中我們可以看出來,今天所要學(xué)的東西包含兩個部分,第一部分是DOM樹,第二部分是遍歷DOM。如果你和我一樣對于DOM樹和遍歷DOM是初次接觸,那個人建議您花點時間好好看看這兩部分的知識罢杉。

DOM樹

眾所周之著洼,HTML文檔的主干就是標記(也就是大家熟悉的HTML標簽元素)绊困。

根據(jù)文檔對象模型(即:DOM)那先,每個HTML標簽事實上都是一個對象。嵌套的標簽被稱為元素(或子標簽)。除此之外慎颗,標簽內(nèi)的文本也是一個對象锚国。而這些對象都可以使用JavaScript訪問。

那么啥是DOM樹呢翔怎?我們先來看看現(xiàn)實生活中的例子窃诉。想象一棵與所有世代有關(guān)系的家庭樹(大家熟知的族譜),其包括了:祖父母赤套、父母飘痛、孩子、兄弟姐妹等等容握。我們通常以等級的方式組織豪庭樹(族譜)宣脉。

image

上圖是一個家族族譜的圖。其中Tossico剔氏、Akikazu塑猖、HitomiTakemi是祖父母。而Toshiakijuliana是父母谈跛。另外TK羊苟、YujiBrunoKaio是父母的孩子(其實也是我的兄弟姐妹們)感憾。

除了家族族譜之外蜡励,生活中還有另一個示例,那就是一個組織的結(jié)構(gòu)層次阻桅,比如:

image

而在HTML中凉倚,DOM其實也類似一棵樹的,它和前面所舉例的家族族譜嫂沉,組織機構(gòu)圖是類似的稽寒,HTML中DOM就是一棵樹

image

DOM的一個示例

我們來看一個DOM的示例输瓜,比如下面這樣的一個HTML文檔:

<pre class="" style="margin: 0px; padding: 0.5em; max-width: 100%; box-sizing: inherit; word-wrap: break-word !important; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.544px; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; overflow: auto; font-family: monospace, monospace; font-size: 14px; background-color: rgb(0, 43, 54); color: rgb(131, 148, 150);">

<!DOCTYPE HTML> <html>
<head>
<title>About elks</title>
</head>
<body>
The truth about elks.
</body> </html>

</pre>

DOM將HMTML表示為標記的樹結(jié)構(gòu)(也就是大家所說的DOM樹)瓦胎,就如下面這樣的樣子:

image

在上面的圖中芬萍,你可以單擊元素的節(jié)點,它們的子節(jié)點可以展開或者收縮搔啊,如下圖所示:

image

HTML的標簽被稱為元素(element)節(jié)點(或只是元素)柬祠。嵌套標簽成為一個子元素(也被稱為子)。因此负芋,對于一個HTML文檔而言漫蛔,<html>是一個根節(jié)點(也被稱為根元素),然后<head><body><html>的子元素。

元素內(nèi)的文本被稱這文本節(jié)點旧蛾,標記為#text莽龟。文本節(jié)點僅包含一個字符串。它可能沒有子元素锨天,也就是說它永遠只是樹的葉子(沒有成為樹枝的可能)毯盈。

除此之外,要注意文本節(jié)點中的兩個特殊字符:

  • 換行符:?(對應(yīng)JavaScript中的\n

  • 空白符:?

空格和換行符是完全有效的字符病袄,它們形成文本節(jié)點并成為DOM的一部分搂赋。因此,例如在<head>標簽之上的示例中益缠,在<title>這前包含了一些空格脑奠,并且該文本成為一個#text節(jié)點(它只包含一條換行符和一些空格)。

不過要注意的是幅慌,有兩個將會除外:

  • <head>標簽之前的空格和換行符由于歷史原因?qū)⒈缓雎?/p>

  • 如果我們將一些東西放在</body>之后宋欺,那么它就會自動地移到</body>的前面,正如HTML規(guī)范要求的一樣胰伍,所有內(nèi)容必須在</body>中一樣齿诞。因此,在</body>之后可能沒有空格

在其他情況之下喇辽,一切都很簡單掌挚。如果文檔中有空格(就像任何字符一樣)雨席,那么它們就會成為DOM中的文本節(jié)點菩咨,如果我們刪除它們,那么就不會有任何東西陡厘,也不再會有空格符或換行符的節(jié)點抽米。

比如下面這個示例:

<pre class="" style="margin: 0px; padding: 0.5em; max-width: 100%; box-sizing: inherit; word-wrap: break-word !important; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.544px; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; overflow: auto; font-family: monospace, monospace; font-size: 14px; background-color: rgb(0, 43, 54); color: rgb(131, 148, 150);">

<!DOCTYPE HTML><html><head><title>About elks</title></head><body>The truth about elks.</body></html>

</pre>

上面的HTML結(jié)構(gòu)對應(yīng)的DOM樹如下圖所示:

image.gif

相比上面的截圖可以看出來,沒有了空格符和換行符的文本節(jié)點糙置。

通過上面的示例云茸,可能你對DOM樹有一定的了解了。但對一些一技術(shù)的定義估計還不是非常的了解谤饭,接下來花點時間來說一下DOM中的一些技術(shù)定義标捺。

DOM中的技術(shù)定義

DOM樹(tree)是一個DOM節(jié)點(nodes)的集合(拿到生活中來說懊纳,樹是稱為節(jié)瞇的實體集合)。而其中節(jié)點由邊(edges)連接亡容。每個節(jié)點(node)都包含一個值(value)或數(shù)據(jù)(data)嗤疯,它可能或有可能沒有子節(jié)點(child node)。

image

treefirst node稱為root節(jié)點闺兢。如果root節(jié)點由另一個節(jié)點連接茂缚,則root節(jié)點是父節(jié)點,連接的節(jié)點是子節(jié)點屋谭。

image

所有的樹節(jié)點(Tree nodes)都被edges連接在一起脚囊。它是樹(trees)的重要組成部分,因為它管理節(jié)點(nodes)之間的關(guān)系桐磁。

image

對于一棵樹而言悔耘,葉子(leaes)是樹(tree)上的最后一個節(jié)點(nodes)。它們是沒有子節(jié)點我擂。就像真正的樹一樣淮逊,DOM也是有根(root)、枝(Element)和葉子(文本節(jié)點)扶踊。

除此之外泄鹏,其他還需要理解的重要概念是高度(height)和深度(depth)。樹的高度是葉子最長路徑的長度秧耗;節(jié)點的深度是路徑到其根的長度备籽。用下圖來闡述會更形象一些:

image

簡單的總結(jié)一些術(shù)語:

  • root(根節(jié)點)是樹(tree)最頂端的節(jié)點

  • edge(邊緣)是兩個節(jié)點(node)之間的連接

  • child(子節(jié)點)是具有父節(jié)點的節(jié)點

  • parent(父節(jié)點)是一個節(jié)點,它具有子節(jié)點的邊緣

  • leaf(樹葉)是樹中沒有子節(jié)點的節(jié)點

  • height(高度)是葉子最長路徑的長度

  • depth(深度)是路徑到其根的長度

有關(guān)于這方面更深入的介紹可以閱讀@TK的《Everything you need to know about tree data structures》一文分井。

另外@TK的文章還涉及到了深度優(yōu)先遍歷廣度優(yōu)秀遍歷车猬,有關(guān)于這兩個概念的深入介紹,可以閱讀:

  • querySelectorAllgetElementsByTagName

  • Demystifying Depth-First Search

  • Breaking Down Breadth-First Search

其實有關(guān)于深度優(yōu)先遍歷廣度優(yōu)秀遍歷在DOM樹中的作用并不明顯尺锚,對于后續(xù)的DOM遍歷還是有很大的影響珠闰。

經(jīng)過的上面的學(xué)習(xí),我們對于DOM樹有了一定的了解瘫辩。除此之外伏嗜,瀏覽器對于DOM還具有自動較正的特性。

自動校正

如果瀏覽器遇到格式錯誤的HTML伐厌,它會自動更正它(校正)承绸。

例如,HTML最頂端的標簽總是<html>挣轨。即使它不存在文檔中 —— 它將存在DOM中军熏,瀏覽器也會創(chuàng)建它。另外<body>也是一樣卷扮。

例如荡澎,HTML文件只包含一個單詞Hello均践,瀏覽器將它放置在成<html><body>中,并且也會添加所需的<head>摩幔。其DOM將是:

image

另外浊猾,生成DOM時,瀏覽器會自動處理文檔中的錯誤热鞍,比如關(guān)閉標簽等等葫慎。比如下面這樣一個無效的文檔:

<pre class="" style="margin: 0px; padding: 0.5em; max-width: 100%; box-sizing: inherit; word-wrap: break-word !important; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.544px; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; overflow: auto; font-family: monospace, monospace; font-size: 14px; background-color: rgb(0, 43, 54); color: rgb(131, 148, 150);">

<p>Hello<li>Mom<li>and<li>Dad

</pre>

事實上,瀏覽器渲染時薇宠,它照樣會成為一個正常的 DOM偷办,那是因為瀏覽器讀取標簽并會自動修復(fù)丟失的部分(比如說關(guān)閉標簽):

image

除此之外,還有一個有趣的“特殊情況”澄港,那就是table(表格元素)椒涯。根據(jù)DOM規(guī)范,它必須有<tbody>回梧,但是如果你在HTML文檔中忘記寫該標簽元素時废岂,瀏覽器會自動在DOM中添加<tbody>標簽。比如:

<pre class="" style="margin: 0px; padding: 0.5em; max-width: 100%; box-sizing: inherit; word-wrap: break-word !important; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.544px; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; overflow: auto; font-family: monospace, monospace; font-size: 14px; background-color: rgb(0, 43, 54); color: rgb(131, 148, 150);">

<table id="table"><tr><td>1</td></tr></table>

</pre>

此時瀏覽器渲染出來的DOM結(jié)構(gòu)如下:

image

其他節(jié)點類型

我們可以在一個HTML文檔中添加更多的標簽和在頁面中添加注釋狱意,比如:

<pre class="" style="margin: 0px; padding: 0.5em; max-width: 100%; box-sizing: inherit; word-wrap: break-word !important; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.544px; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; overflow: auto; font-family: monospace, monospace; font-size: 14px; background-color: rgb(0, 43, 54); color: rgb(131, 148, 150);">

<!DOCTYPE HTML> <html>
<body>
The truth about elks.
<ol>
<li>An elk is a smart</li>

<li>...and cunning animal!</li>
</ol>
</body> </html>

</pre>

對于上面的HTML文檔湖苞,其對應(yīng)的DOM樹如下圖所示:

image

上圖中,我們看到了一個新的節(jié)點類型 —— 注釋節(jié)點详囤,標記為 #comment财骨。

你可能會想,為什么要將注釋添加到DOM中呢藏姐?它不會以任何方式影響視覺上的效果隆箩,但是有一個規(guī)則,如果某個東西在HTML中羔杨,那么它也必須在DOM樹中捌臊。

HTML中的一切,甚至是注釋兜材,都將成為DOM的一部分理澎。

即使是<!DOCTYPE ...>指令也是一個DOM節(jié)點。它在DOM樹中护姆,在<html>之前矾端。我們不會去觸摸那個節(jié)點,我們甚至不會在圖上畫它卵皂,但它卻實實大大的存在那里。

document對象也是一個DOM節(jié)點砚亭,表示整個文檔灯变。在DOM中殴玛,其有12種節(jié)點類型。在實際操作中添祸,我們通常使用4種方法:

  • document:進入DOM的入口點

  • 元素節(jié)點:HTML標簽滚粟,樹構(gòu)建塊

  • 文本節(jié)點:包含文本

  • 注釋:有時候我們可以把信息放在這里,但它不會顯示出來刃泌,不過JavaScript卻可以從DOM中讀取它

或許你和我一樣凡壤,希望能對每個HTML文檔對應(yīng)的DOM結(jié)構(gòu)能實時的查看,我們希望有對應(yīng)的工具能幫助我們耙替。事實上是有類似這樣的工具亚侠,比如 Live DOM Viewer。只要輸入文檔俗扇,它就會立即顯示DOM樹結(jié)構(gòu)硝烂。

DOM中的空白符

DOM 中的空白符會讓處理節(jié)點結(jié)構(gòu)時增加不少麻煩。在Mozilla 的軟件中铜幽,原始文件里所有空白符都會在 DOM 中出現(xiàn)(不包括標簽內(nèi)含的空白符)滞谢。這樣的處理方式有其必要之處,一方面編輯器中可逕行排列文字除抛、二方面 CSS 里的 white-space: pre 也才能發(fā)揮作用狮杨。 如此一來就表示:

  • 有些空白符會自成一個文本節(jié)點。

  • 有些空白符會與其他文本節(jié)點合成為一個文本節(jié)點到忽。

換句話說禾酱,下面這段 HTML 代碼對應(yīng)的 DOM 節(jié)點結(jié)構(gòu)會如附圖所示,其中\n代表換行符:

<pre class="" style="margin: 0px; padding: 0.5em; max-width: 100%; box-sizing: inherit; word-wrap: break-word !important; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.544px; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; overflow: auto; font-family: monospace, monospace; font-size: 14px; background-color: rgb(0, 43, 54); color: rgb(131, 148, 150);">

<html>
<head>
<title>My Document</title>
</head>
<body>
<h1>Header</h1>
<p>
Paragraph
</p>
</body> </html>

</pre>

對應(yīng)的DOM樹绘趋,如下圖所示:

image

這么一來颤陶,要使用 DOM 游走于節(jié)點結(jié)構(gòu)間又不想要無用的空白符時,會有點困難陷遮。

以下的 JavaScript 代碼定義了許多函數(shù)滓走,能夠讓你在處理 DOM 中的空白符時輕松點:

image
image
image
image

DOM的遍歷

如果你閱讀了上面的的內(nèi)容,或許你已經(jīng)意識到帽馋,DOM看起來就像一個巨大的樹 —— 一棵巨大的樹搅方,它的元素掛載在樹枝上。為了獲得更多的技術(shù)绽族,DOM中的元素被安排在一個層次結(jié)構(gòu)中姨涡,它定義了你最終在瀏覽器中看到的內(nèi)容:

image

這個層次結(jié)構(gòu)用于幫助我們組織HTML元素。它還用于幫助你的CSS樣式規(guī)則理解什么樣式適用于哪些東西吧慢。從JavaScript角度來看涛漂,這個層次結(jié)構(gòu)確實增加了一點復(fù)雜性。你會花相當多的時間去弄清楚你現(xiàn)在所有的DOM和你需要去的地方。當我們考慮創(chuàng)建新的元素或移動元素時匈仗,這將變得更加明顯瓢剿。這種復(fù)雜性是你需要適應(yīng)的。

找到你的方式

在你找到元素并與它們做一些事情之前悠轩,你首先需要了解元素的位置间狂。我解決這個問題,最簡單的方法就是從頭開始火架,然后一路向下鉴象。這就是我們要做的。

為了更易于幫助在大家理解何鸡,先回到上一節(jié)中的示例中:

<pre class="" style="margin: 0px; padding: 0.5em; max-width: 100%; box-sizing: inherit; word-wrap: break-word !important; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.544px; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; overflow: auto; font-family: monospace, monospace; font-size: 14px; background-color: rgb(0, 43, 54); color: rgb(131, 148, 150);">

<!DOCTYPE html>
<html>
<head>
<meta content="DOM, JavaScript, W3cplus" name="keywords" />
<meta content="DOM系列纺弊,瀏覽器和DOM!" name="description" />
<title>LOL! Sea Otter! Little Kid!</title>
<link href="style.css" rel="stylesheet"/>
</head>
<body>
<div id="container">
<img src="w3cplus_logo.png"/>
<h1>DOM系列學(xué)習(xí)!</h1>
<p class="bodyText">開始學(xué)習(xí)DOM,這是一個有關(guān)于DOM學(xué)習(xí)的系列教程...<p>
<div class="submitButton">next</div>
</div>
<script src="main.js"></script>
</body>
</html>

</pre>

來自DOM頂部的視圖由window音比、documenthtml元素組成:

image.gif

由于這三樣?xùn)|西的重要性俭尖,DOM為你提供了通過windowdocumentdocument.documentElement訪問它們的方法洞翩。

<pre class="" style="margin: 0px; padding: 0.5em; max-width: 100%; box-sizing: inherit; word-wrap: break-word !important; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.544px; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; overflow: auto; font-family: monospace, monospace; font-size: 14px; background-color: rgb(0, 43, 54); color: rgb(131, 148, 150);">

var windowObject = window;
var documentObject = document; var htmlElement = document.documentElement;

</pre>

需要注意的一點是稽犁,windowdocument都是全局屬性。不必要明確的聲明它們骚亿,可以直接從容器里拿出來用就行了已亥。

往往,最頂層的樹節(jié)點可以直接作為document屬性使用来屠,比如:

<pre class="" style="margin: 0px; padding: 0.5em; max-width: 100%; box-sizing: inherit; word-wrap: break-word !important; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.544px; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; overflow: auto; font-family: monospace, monospace; font-size: 14px; background-color: rgb(0, 43, 54); color: rgb(131, 148, 150);">

<html> = document.documentElement

</pre>

頂部文檔節(jié)點document.documentElement虑椎,其對應(yīng)的就是<html>的DOM節(jié)點。另外一個廣泛使用的DOM節(jié)點是<body>元素俱笛,其對應(yīng)的是document.body

<pre class="" style="margin: 0px; padding: 0.5em; max-width: 100%; box-sizing: inherit; word-wrap: break-word !important; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.544px; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; overflow: auto; font-family: monospace, monospace; font-size: 14px; background-color: rgb(0, 43, 54); color: rgb(131, 148, 150);">

<body> = document.body

</pre>

同樣的捆姜,<head>標簽可以用document.head

不過有一點需要注意:

document.body有可能為null迎膜。當腳本在訪問不存在的元素時泥技,返回的值將會為null

比如磕仅,當你的腳本在</head>中運行珊豹,比如document.body是將返回的值將是null,因為瀏覽器還沒有讀取它榕订。但在</body>中的<script>中返回的則是<body>元素:

<pre class="" style="margin: 0px; padding: 0.5em; max-width: 100%; box-sizing: inherit; word-wrap: break-word !important; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.544px; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; overflow: auto; font-family: monospace, monospace; font-size: 14px; background-color: rgb(0, 43, 54); color: rgb(131, 148, 150);">

<html>
<head>
<script> console.log('From head:', document.body) // => null</script>
</head>
<body>
<script> console.log('From body:', document.body) // => HTMLBodyElement</script>
</body> </html>

</pre>

上面我們所看到的是html店茶、headbody元素的獲取。但事實上劫恒,一旦你進入HTML元素級別贩幻,你的DOM將開始分支并變得更有趣。在這一點上,你有幾種獲取DOM的方式段直。通過使用querySelector()querySelectorAll()可以幫助你精確地獲取你想要獲取的DOM元素吃溅∪艿或許你已經(jīng)在項目中大量使用這兩種方法了鸯檬。但事實上,對于許多實際案例來說螺垢,這兩種方法太過局限喧务。

有時候,你不知道你想去哪里枉圃。querySelector()querySelectorAll()主法在這里無法幫助您功茴。你只想上車然后開車,并想找到你想要去的地方孽亲】泊回到DOM的世界當中時,你會發(fā)現(xiàn)自己一直處理這個位置返劲。這就是DOM提供的各種內(nèi)置屬性玲昧,所有的Motorcycle Diaries將會幫助你,接下來我們將看看這些屬性篮绿。

能夠幫助你的是知道所有的DOM元素都至少有一個組合孵延,包括父母(Parents)兄弟姐妹(Siblings)子元素(Children)亲配。為了更直觀的幫助大家理解尘应,來看下圖,下圖中包含divscript的一個樹形圖:

image

divscript兄弟元素吼虎。他們是兄弟元素的原因是他們共有一個相同的父元素body犬钢。script元素沒有子元素,但是div元素有四個子元素思灰,img玷犹、h1pdiv官辈。這四個元素也相互被稱為兄弟元素箱舞,同樣的是因為他們有相同的父元素。這其實很好理解拳亿,如果你閱讀了文章前面的DOM樹相關(guān)的內(nèi)容晴股,你會發(fā)現(xiàn)它們就像現(xiàn)實的生活中一樣,父母肺魁、孩子 和兄弟姐妹的關(guān)系基于你所關(guān)注的樹的位置(對應(yīng)的就是家族族譜)电湘。幾乎每個元素,取決于你看它們的角度,可以扮演多個家庭角色寂呛。

為了更好的理解怎诫,DOM中提供了一些對應(yīng)的屬性(這些屬性具有一定的依賴關(guān)系)。包括:firstChild贷痪、lastChild幻妓、parentNodechildren劫拢、previousSiblingnextSibling肉津。從他們的名稱上來看,就可以推出這些屬性的作用舱沧。這幾個屬性結(jié)合在一起將構(gòu)建一個DOM遍歷鏈接圖发钝,允許在DOM節(jié)點間找到你想要找到的DOM:

image

為了更好的理解DOM遍歷相關(guān)的知識點简烤,咱們接下來將圍繞這幾個屬性來展開幽邓。

兄弟姐妹和父母打交道

在這些DOM屬性中娶吞,最容易處理的是父母和兄弟姐妹。對應(yīng)的屬性有parentNode牵寺、previousSiblingnextSibling悍引。下面這張圖將幫助你了解這三個屬性是如何工作的:

image

這張圖雖然有點零亂,但是你仔細看的話缸剪,你可以理清楚它們之間的關(guān)系吗铐,以及他們之間發(fā)生了什么。parentNode屬性指向元素的父元素杏节。previousSiblingnextSibling屬性允許元素元素它的前一個或下一個兄弟元素唬渗。你可以在圖中看到箭頭的方向指向。最后一行奋渔,imgnextSiblingdiv镊逝,相應(yīng)的divpreviousSiblingimg元素。不管是通過imgdivparentNode屬性都將把我們帶入到第二行中的div(事實上就是imgdiv的元素)嫉鲸。通過上圖撑蒜,大家理解起來是不是很簡單。

子元素打交道

上面咱們看到的是如何通過DOM的屬性來訪問兄弟元素和父元素玄渗,事實上座菠,除此之外,DOM還提供一些屬性可以訪問元素的子元素藤树,比如firstChild浴滴、lastChildchildren。同樣用一圖來向大家展示:

image

firstChildlastChild屬性是指父元素的第一個和最后一個子元素岁钓。如果父類只有一個子元素升略,就像例子中的body元素一樣微王,firstChildlastChild都指向相同的元素div。如果一個元素沒有子元素品嚣,那么firstChildlastChild屬性將返回一個null炕倘。

與其他屬性相比,其中children屬性相對而方要更為復(fù)雜一些翰撑。當你在父類上訪問children屬性時罩旋,基本上會得到父元素的子元素集合。這個集合并不是數(shù)組额嘿,但它確實有一些類似數(shù)組的能力瘸恼,就是大家所說的類數(shù)組劣挫,其具有length屬性册养,可以通過[]item()來索引集合中具體的元素。比如上圖中的div.children[0]訪問到的是第一個img元素压固。

在DOM中獲取子節(jié)點球拦,除了前面提到的三個屬性之外,還有一個childNodes屬性帐我,不過它和children有一個很明顯的區(qū)別:

children只獲取子節(jié)點(即子元素)坎炼,而childNodes除了獲取的子節(jié)點還包括文本節(jié)點

除此之外拦键,還有一個特殊的函數(shù)hasChildNodes()可以用來判斷某個元素是否包含子節(jié)點谣光。

這個時候,你把它們放在一起芬为,你就可以對DOM進行遍歷萄金。也可以做一些事情。比如媚朦,檢查某個元素是否有子元素存在氧敢,我們就可以這樣做:

<pre class="" style="margin: 0px; padding: 0.5em; max-width: 100%; box-sizing: inherit; word-wrap: break-word !important; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.544px; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; overflow: auto; font-family: monospace, monospace; font-size: 14px; background-color: rgb(0, 43, 54); color: rgb(131, 148, 150);">

let bodyElement = document.body
if (bodyElement.firstChild) {
// 這里做你想做的事情... }

</pre>

如果body沒有子節(jié)點,那么if語獎將返回null询张。當然孙乖,你也可以使用bodyElement.lastChildbodyElement.children做為if語句的條件。

再來看另一個簡單示例份氧,前面提到過了唯袄,通過children可以獲取某個元素的所有子節(jié)點(前提是這個元素有子元素存在)。這個時候得到的是一個類數(shù)組蜗帜,如查你要獲取到該元素中的每個子節(jié)點恋拷,就需要使用for循環(huán)來處理:

<pre class="" style="margin: 0px; padding: 0.5em; max-width: 100%; box-sizing: inherit; word-wrap: break-word !important; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.544px; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial; overflow: auto; font-family: monospace, monospace; font-size: 14px; background-color: rgb(0, 43, 54); color: rgb(131, 148, 150);">

var bodyElement = document.body;
for (var i = 0; i < bodyElement.children.length; i++) {
var childElement = bodyElement.children[i];
document.writeln(childElement.tagName);
}

</pre>

通過元素遍歷DOM

上面咱們看到的是通過DOM節(jié)點來遍歷DOM。比如childNodes屬性钮糖,除了可以獲取元素節(jié)點之外梅掠,還可以獲取文本節(jié)點酌住,甚至是注釋節(jié)點。但很多時候阎抒,對于DOM的操作酪我,咱們只需要獲取想要的DOM元素節(jié)點,而不需要考慮文本和注釋節(jié)點且叁。這個時候咱們只需要操作元素節(jié)點即可都哭,這對應(yīng)DOM中操作元素節(jié)點的一些屬性。同樣的使用下圖來向大家闡述逞带,易于理解:

image

和前面相比欺矫,這里的屬性多了Element這個詞,其對應(yīng)的含義:

  • children:元素節(jié)點的子元素

  • firstElementChild展氓、lastElementChild:元素的第一個或最后一個子元素

  • previousElementSiblingnextElementSibling:元素的前一個或后一個相鄰元素

  • parentElement:元素的父元素

總結(jié)

這篇文章是DOM系列的第二篇文章穆趴,主要介紹了DOM樹和DOM的遍歷。前一部分只要介紹了DOM樹遇汞,簡單的理解未妹,任何一個HTML文檔都可以類似于家族的族普來繪制對應(yīng)的DOM樹。通過DOM樹可以理清楚每個DOM元素(或者說DOM節(jié)點)之間的關(guān)系空入。比如络它,父子關(guān)系、兄弟關(guān)系等歪赢。

另外化戳,在DOM中找到對應(yīng)的元素是每位JavaScript開發(fā)人員都應(yīng)該需要掌握的技巧之一。這篇文章的后一部分主要向大家介紹了如何對DOM進行遍歷埋凯,其實就是通過DOM的屬性怎么獲取DOM的元素或節(jié)點点楼。簡單的歸納一下,分為:

  • 向上獲取递鹉,比如parentNode盟步、parentElementclosest

  • 向下獲取躏结,比如querySelector()却盘、querySelectorAll()children媳拴、firstChildren黄橘、lastChildrenchildNodes

  • 兄弟元素(節(jié)點),比如nextElementSibling屈溉、previousElementSibling塞关、nextSiblingpreviousSibling

如果文中有不對之處,或者你有更好的經(jīng)驗子巾,歡迎在下面的評論中與我們一起分享帆赢。最后要說明的是小压,文章中有些圖片來自互聯(lián)網(wǎng),如涉及侵權(quán)椰于,煩請告之怠益。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市瘾婿,隨后出現(xiàn)的幾起案子蜻牢,更是在濱河造成了極大的恐慌,老刑警劉巖偏陪,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件抢呆,死亡現(xiàn)場離奇詭異,居然都是意外死亡笛谦,警方通過查閱死者的電腦和手機抱虐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來揪罕,“玉大人梯码,你說我怎么就攤上這事『脝” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵儿奶,是天一觀的道長框往。 經(jīng)常有香客問我,道長闯捎,這世上最難降的妖魔是什么椰弊? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮瓤鼻,結(jié)果婚禮上秉版,老公的妹妹穿的比我還像新娘。我一直安慰自己茬祷,他們只是感情好清焕,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著祭犯,像睡著了一般秸妥。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上沃粗,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天粥惧,我揣著相機與錄音,去河邊找鬼最盅。 笑死突雪,一個胖子當著我的面吹牛起惕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播咏删,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼疤祭,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了饵婆?” 一聲冷哼從身側(cè)響起勺馆,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎侨核,沒想到半個月后草穆,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡搓译,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年悲柱,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片些己。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡豌鸡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出段标,到底是詐尸還是另有隱情涯冠,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布逼庞,位于F島的核電站蛇更,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏赛糟。R本人自食惡果不足惜派任,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望璧南。 院中可真熱鬧掌逛,春花似錦、人聲如沸司倚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽对湃。三九已至崖叫,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間拍柒,已是汗流浹背心傀。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留拆讯,地道東北人脂男。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓养叛,卻偏偏與公主長得像,于是被迫代替她去往敵國和親宰翅。 傳聞我的和親對象是個殘疾皇子弃甥,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容