iT邦幫忙

2021 iThome 鐵人賽

DAY 19
0
自我挑戰組

JavaScript老學徒筆記—馬步篇系列 第 20

文件物件模型--DOM

BOM(Browser Object Model 瀏覽器物件模型)的重點在於瀏覽器的功能,完全由各家瀏覽器廠商自行開發。而DOM(Document Object Model 文件物件模型)則是W3C所制定的共同文件規範,提供跨瀏覽器且標準的文件處理介面。

DOM(Document Object Model 文件物件模型),是一個有階層的樹狀結構,一個節點就是一個標籤,根節點下有子節點,子節點下還有子節點,形成上下結構的關係,這樣的樹狀結構,我們稱之為「DOM Tree」。

《0陷阱!0誤解!8天重新認識JavaScript》一書中有提到:

「DOM API定義了讓JavaScript可以存取、改變HTML架構、樣式和內容的方法,甚至對節點綁定的事件。」

當瀏覽器載入一個網頁時,瀏覽器會分析這個網頁的HTML,依照它的HTML結構建立一個DOM Tree。DOM的學習重點就在於掌握節點根結點之間的關係,學會如何控制DOM就可以控制網頁,做出良好的互動體驗。

如何透過DOM API取得節點:

//根據傳入的id 名稱,找到DOM裡面相同id名稱的節點。
document.getElementById('idName');

//根據傳入的tag名稱,回傳所有符合條件的NodeList物件。
document.getEleMentsByTagName('tagName');

//根據傳入的class名稱,回傳所有符合條件的NodeList物件。
document.getElementByClassName('className')

//根據所設定的selector條件(class或id都可以),回傳第一個符合條件的節點。
document.querySelector('selector');

//根據所給定的selector條件,回傳所有符合條件的 NodeList。
document.querySelectorAll;

假設網頁上有一個h1的標籤節點,裡面沒有任何內容:

<h1 id="hello"></h1>

我們利用document.getElementById('hello')來取得#hello節點,然後修改textContent屬性:

document.getElementById('hello').textContent = '郭靖在華山論劍向大家說 Hello World!'

這就是取得節點,改變HTML內容的方法。

你有發現嗎?不管是document.getElementById('idName') 或是document.querySelector('selector')都是由document開頭。讓我們來看看DOM Tree的圖,可以發現document是整個DOM Tree的根結點,所以在存取DOM節點時,都要從document出發。

我們觀察一下DOM Tree的圖可以發現,節點之間有上下分層的關係,也有同一層節點間相鄰的關係,所以節點與節點之間的關係可以區分為:

  • 父子關係:document在最上層,其他的節點若有上層的節點,上層的節點稱為「父節點」(Parent Node),下層的節點稱為「子節點」(Child Node)。就像王陽明的徒弟是「全真七子」,而全真七子之一的丘處機,他的徒弟是尹志平等人。
  • 兄弟關係:同一層的節點如果它們有同一個「父節點」,那它們之間就是「兄弟關係」,就像王陽明的徒弟「全真七子」,他們之間是師兄弟關係。

Node.childNodes

「所有的DOM節點物件都有childNodes屬性,且這種屬性無法修改」,那我們要如何知道一個節點是否有子節點? 這時候可以利用Node.hasChildNodes()來檢查:

<div id="sword">
  <ul>
    <li>1 東邪</li>
    <li>2 西毒</li>
    <li>3 南帝</li>
    <li>4 北丐</li>
    <li>5 中神通</li>
  </ul>
</div>
var node = document.getElementById('sword');

if(node.hasChildNodes()){
  for(var i=0; i <node.childNodes.length; i++)
    console.log(i + node.childNodes[i].nodeName);
}

來看一下console出來的結果:

cosole視窗中列出了查詢的結果,我為查詢的節點加上了編號,除了"LI"之外,還出現了"0#text"之類的字串,這是因為換行符號的空白節點也被查詢了出來。如果不換行的話,"0#text"就不會出現。

Node.firstChild

Node.firstChild用來取得Node節點的第一個子節點,如果沒有子節點的話,則回傳null。而子節點包括空白節點,例如HTML Tag之間的換行符號。

<div id="sword">
  <ul id="fiveHero"><li class="firstHero">1 東邪</li><li>2 西毒</li><li>3 南帝</li><li>4 北丐</li><li>5 中神通</li>
  </ul>
</div>
var node = document.getElementById('fiveHero');
console.log(node.firstChild.className);   //firstHero

Node.lastChild

Node.lastChild可以取得Node節點的最後一個子節點,如果沒有子節點的話,則一樣是傳回null。而子節點包括空白節點,例如HTML Tag之間的換行符號。

<div id="sword">
  <ul id="fiveHero"><li class="firstHero">1 東邪</li><li>2 西毒</li><li>3 南帝</li><li>4 北丐</li><li class="lastHero">5 中神通</li></ul>
</div>
var node = document.getElementById('fiveHero');
console.log(node.lastChild.className);         //"lastHero"

Node.parentNode

Node.parentNode可以取得Node節點的父節點。

<div id="sword">
  <ul id="fiveHero"><li class="firstHero">1 東邪</li><li>2 西毒</li><li>3 南帝</li><li>4 北丐</li><li class="lastHero">5 中神通</li></ul>
</div>
var node = document.getElementById('fiveHero');
console.log(node.parentNode.tagName);          //"DIV"

Node.previousSibling

有同一個父元素,位於同一層的節點稱為「兄弟節點」,而Node.previousSibling可以取得Node節點的前一個兄弟節點。

<div id="sword">
  <ul id="fiveHero">
    <li class="firstHero">1 東邪</li><li class="secondHero">2 西毒</li><li class="thirdHero">3 南帝</li><li class="fifthHero">4 北丐</li><li class="lastHero">5 中神通</li>
  </ul>
</div>
var node = document.querySelector('.secondHero');
console.log(node.previousSibling.className);     //"firstHero"

Node.nextSibling

Node.nextSibling可以取得Node節點的下一個兄弟節點。

<div id="sword">
  <ul id="fiveHero">
    <li class="firstHero">1 東邪</li><li class="secondHero">2 西毒</li><li class="thirdHero">3 南帝</li><li class="fifthHero">4 北丐</li><li class="lastHero">5 中神通</li>
  </ul>
</div>
var node = document.querySelector('.secondHero');
console.log(node.nextSibling.className);       //"thirdHero"

由上面幾個操作,可以知道透過節點的抓取,我們可以取得節點的資訊,進而改變網頁的結構、內容以及樣式,懂得控制節點,就可以控制網頁的呈現與使用者互動。


上一篇
【Day18】瀏覽器物件模型--BOM
下一篇
【Day20】比較Nodelist與HTML collection的差異
系列文
JavaScript老學徒筆記—馬步篇35
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言