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的圖可以發現,節點之間有上下分層的關係,也有同一層節點間相鄰的關係,所以節點與節點之間的關係可以區分為:
「所有的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節點的第一個子節點,如果沒有子節點的話,則回傳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節點的最後一個子節點,如果沒有子節點的話,則一樣是傳回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節點的父節點。
<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節點的前一個兄弟節點。
<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節點的下一個兄弟節點。
<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"
由上面幾個操作,可以知道透過節點的抓取,我們可以取得節點的資訊,進而改變網頁的結構、內容以及樣式,懂得控制節點,就可以控制網頁的呈現與使用者互動。