JavaScript中DOM基礎

DOM(Document Object Model)即文檔對象模型,針對HTML 和XML 文檔的API(應
用程序接口)。DOM 描繪了一個層次化的節點樹,運行開發人員添加、移除和修改頁面的
某一部分。DOM 脫胎於Netscape 及微軟公司創始的DHTML(動態HTML),但現在它已
經成爲表現和操作頁面標記的真正跨平臺、語言中立的方式。

一.DOM介紹
DOM 中的三個字母,D(文檔)可以理解爲整個Web 加載的網頁文檔;O(對象)可
以理解爲類似window 對象之類的東西,可以調用屬性和方法,這裏我們說的是document
對象;M(模型)可以理解爲網頁文檔的樹型結構。
DOM 有三個等級,分別是DOM1、DOM2、DOM3,並且DOM1 在1998 年10 月成爲
W3C 標準。DOM1 所支持的瀏覽器包括IE6+、Firefox、Safari、Chrome 和Opera1.7+。
PS:IE 中的所有DOM 對象都是以COM 對象的形式實現的,這意味着IE 中的DOM
可能會和其他瀏覽器有一定的差異。

1.節點
加載HTML 頁面時,Web 瀏覽器生成一個樹型結構,用來表示頁面內部結構。DOM 將
這種樹型結構理解爲由節點組成。

從上圖的樹型結構,我們理解幾個概念,html 標籤沒有父輩,沒有兄弟,所以html 標
籤爲根標籤。head 標籤是html 子標籤,meta 和title 標籤之間是兄弟關係。如果把每個標籤
當作一個節點的話,那麼這些節點組合成了一棵節點樹。
PS:後面我們經常把標籤稱作爲元素,是一個意思。

2.節點種類:元素節點、文本節點、屬性節點。

二.查找元素
W3C 提供了比較方便簡單的定位節點的方法和屬性,以便我們快速的對節點進行操作。
分別爲:getElementById()、getElementsByTagName()、getElementsByName()、getAttribute()、
setAttribute()和removeAttribute()。

1.getElementById()方法
getElementById()方法,接受一個參數:獲取元素的ID。如果找到相應的元素則返回該
元素的HTMLDivElement 對象,如果不存在,則返回null。

  1. document.getElementById('box'); //獲取id 爲box 的元素節點 

PS:上面的例子,默認情況返回null,這無關是否存在id="box"的標籤,而是執行順序
問題。解決方法,1.把script 調用標籤移到html 末尾即可;2.使用onload 事件來處理JS,等
待html 加載完畢再加載onload 事件裏的JS。

  1. window.onload = function () { //預加載html 後執行 
  2. document.getElementById('box'); 
  3. }; 

PS:id 表示一個元素節點的唯一性,不能同時給兩個或以上的元素節點創建同一個命
名的id。某些低版本的瀏覽器會無法識別getElementById()方法,比如IE5.0-,這時需要做
一些判斷,可以結合上章的瀏覽器檢測來操作。

  1. if (document.getElementById) { //判斷是否支持getElementById 
  2. alert('當前瀏覽器支持getElementById'); 

當我們通過getElementById()獲取到特定元素節點時,這個節點對象就被我們獲取到了,
而通過這個節點對象,我們可以訪問它的一系列屬性。

  1. document.getElementById('box').tagName; //DIV 
  2. document.getElementById('box').innerHTML; //測試Div 

 

 

  1. document.getElementById('box').id; //獲取id 
  2. document.getElementById('box').id = 'person'//設置id 
  3. document.getElementById('box').title; //獲取title 
  4. document.getElementById('box').title = '標題' //設置title 
  5. document.getElementById('box').style; //獲取CSSStyleDeclaration 對象 
  6. document.getElementById('box').style.color; //獲取style 對象中color 的值 
  7. document.getElementById('box').style.color = 'red'//設置style 對象中color 的值 
  8. document.getElementById('box').className; //獲取class 
  9. document.getElementById('box').className = 'box'//設置class 
  10. alert(document.getElementById('box').bbb); //獲取自定義屬性的值,非IE 不支持 

2.getElementsByTagName()方法

getElementsByTagName()方法將返回一個對象數組HTMLCollection(NodeList),這個數
組保存着所有相同元素名的節點列表。

  1. document.getElementsByTagName('*'); //獲取所有元素 

PS:IE 瀏覽器在使用通配符的時候,會把文檔最開始的html 的規範聲明當作第一個元
素節點。

  1. document.getElementsByTagName('li'); //獲取所有li 元素,返回數組 
  2. document.getElementsByTagName('li')[0]; //獲取第一個li 元素,HTMLLIElement 
  3. document.getElementsByTagName('li').item(0) //獲取第一個li 元素,HTMLLIElement 
  4. document.getElementsByTagName('li').length; //獲取所有li 元素的數目 

PS:不管是getElementById 還是getElementsByTagName,在傳遞參數的時候,並不是
所有瀏覽器都必須區分大小寫,爲了防止不必要的錯誤和麻煩,我們必須堅持養成區分大小
寫的習慣。

3.getElementsByName()方法


getElementsByName()方法可以獲取相同名稱(name)的元素,返回一個對象數組
HTMLCollection(NodeList)。

  1. document.getElementsByName('add'//獲取input 元素 
  2. document.getElementsByName('add')[0].value //獲取input 元素的value 值 
  3. document.getElementsByName('add')[0].checked //獲取input 元素的checked 值 

PS:對於並不是HTML 合法的屬性,那麼在JS 獲取的兼容性上也會存在差異,IE 瀏
覽器支持本身合法的name 屬性,而不合法的就會出現不兼容的問題。

4.getAttribute()方法
getAttribute()方法將獲取元素中某個屬性的值。它和直接使用.屬性獲取屬性值的方法有
一定區別。

  1. document.getElementById('box').getAttribute('id');//獲取元素的id 值 
  2. document.getElementById('box').id; //獲取元素的id 值 
  3. document.getElementById('box').getAttribute('mydiv');//獲取元素的自定義屬性值 
  4. document.getElementById('box').mydiv //獲取元素的自定義屬性值,非IE 不支持 
  5. document.getElementById('box').getAttribute('class');//獲取元素的class 值,IE 不支持 
  6. document.getElementById('box').getAttribute('className');//非IE 不支持 

PS:HTML 通用屬性style 和 更低的版本style 返回一個對象,onclick 返回
一個函數式。雖然IE8 已經修復這個bug,但爲了更好的兼容,開發人員只有儘可能避免使
用getAttribute()訪問HTML 屬性了,或者碰到特殊的屬性獲取做特殊的兼容處理。


5.setAttribute()方法
setAttribute()方法將設置元素中某個屬性和值。它需要接受兩個參數:屬性名和值。如果屬性本身已存在,那麼就會被覆蓋。

  1. document.getElementById('box').setAttribute('align','center');//設置屬性和值 
  2. document.getElementById('box').setAttribute('bbb','ccc');//設置自定義的屬性和值 

PS:在IE7 及更低的版本中,使用setAttribute()方法設置class 和style 屬性是沒有效果
的,雖然IE8 解決了這個bug,但還是不建議使用。


6.removeAttribute()方法
removeAttribute()可以移除HTML 屬性。

  1. document.getElementById('box').removeAttribute('style');//移除屬性 

PS:IE6 及更低版本不支持removeAttribute()方法。


三.DOM節點
1.node 節點屬性
節點可以分爲元素節點、屬性節點和文本節點,而這些節點又有三個非常有用的屬性,
分別爲:nodeName、nodeType 和nodeValue。

 

  1. document.getElementById('box').nodeType; //1,元素節點 

2.層次節點屬性
節點的層次結構可以劃分爲:父節點與子節點、兄弟節點這兩種。當我們獲取其中一個
元素節點的時候,就可以使用層次節點屬性來獲取它相關層次的節點。

1.childNodes 屬性
childeNodes 屬性可以獲取某一個元素節點的所有子節點,這些子節點包含元素子節點
和文本子節點。

  1. var box = document.getElementById('box'); //獲取一個元素節點 
  2. alert(box.childNodes.length); //獲取這個元素節點的所有子節點 
  3. alert(box.childNodes[0]); //獲取第一個子節點對象 

PS:使用childNodes[n]返回子節點對象的時候,有可能返回的是元素子節點,比如
HTMLElement;也有可能返回的是文本子節點,比如Text。元素子節點可以使用nodeName
或者tagName 獲取標籤名稱,而文本子節點可以使用nodeValue 獲取。

  1. for (var i = 0; i < box.childNodes.length; i ++) { 
  2. //判斷是元素節點,輸出元素標籤名 
  3. if (box.childNodes[i].nodeType === 1) { 
  4. alert('元素節點:' + box.childNodes[i].nodeName); 
  5. //判斷是文本節點,輸出文本內容 
  6. else if (box.childNodes[i].nodeType === 3) { 
  7. alert('文本節點:' + box.childNodes[i].nodeValue); 

PS:在獲取到文本節點的時候,是無法使用innerHTML 這個屬性輸出文本內容的。這
個非標準的屬性必須在獲取元素節點的時候,才能輸出裏面包含的文本。

  1. alert(box.innerHTML); //innerHTML 和nodeValue 第一個區別 

PS:innerHTML 和nodeValue 第一個區別,就是取值的。那麼第二個區別就是賦值的時
候,nodeValue 會把包含在文本里的HTML 轉義成特殊字符,從而達到形成單純文本的效果。

  1. box.childNodes[0].nodeValue = '<strong>abc</strong>';//結果爲:<strong>abc</strong> 
  2. box.innerHTML = '<strong>abc</strong>'//結果爲:abc 

2.firstChild 和lastChild 屬性
firstChild 用於獲取當前元素節點的第一個子節點,相當於childNodes[0];lastChild 用於
獲取當前元素節點的最後一個子節點,相當於childNodes[box.childNodes.length - 1]。

  1. alert(box.firstChild.nodeValue); //獲取第一個子節點的文本內容 
  2. alert(box.lastChild.nodeValue); //獲取最後一個子節點的文本內容 

3.ownerDocument 屬性
ownerDocument 屬性返回該節點的文檔對象根節點,返回的對象相當於document。

  1. alert(box.ownerDocument === document); //true,根節點 

4.parentNode、previousSibling、nextSibling 屬性
parentNode 屬性返回該節點的父節點,previousSibling 屬性返回該節點的前一個同級節
點,nextSibling 屬性返回該節點的後一個同級節點。

  1. alert(box.parentNode.nodeName); //獲取父節點的標籤名 
  2. alert(box.lastChild.previousSibling); //獲取前一個同級節點 
  3. alert(box.firstChild.nextSibling); //獲取後一個同級節點 

5.attributes 屬性
attributes 屬性返回該節點的屬性節點集合。

  1. document.getElementById('box').attributes //NamedNodeMap 
  2. document.getElementById('box').attributes.length;//返回屬性節點個數 
  3. document.getElementById('box').attributes[0]; //Attr,返回最後一個屬性節點 
  4. document.getElementById('box').attributes[0].nodeType; //2,節點類型 
  5. document.getElementById('box').attributes[0].nodeValue; //屬性值 
  6. document.getElementById('box').attributes['id']; //Attr,返回屬性爲id 的節點 
  7. document.getElementById('box').attributes.getNamedItem('id'); //Attr 

6.忽略空白文本節點

  1. var body = document.getElementsByTagName('body')[0];//獲取body 元素節點 
  2. alert(body.childNodes.length); //得到子節點個數,IE3 個,非IE7 個 

PS:在非IE 中,標準的DOM 具有識別空白文本節點的功能,所以在火狐瀏覽器是7
個,而IE 自動忽略了,如果要保持一致的子元素節點,需要手工忽略掉它。

  1. function filterSpaceNode(nodes) { 
  2. var ret = []; //新數組 
  3. for (var i = 0; i < nodes.length; i ++) { 
  4. //如果識別到空白文本節點,就不添加數組 
  5. if (nodes[i].nodeType == 3 && /^\s+$/.test(nodes[i].nodeValue)) continue
  6. //把每次的元素節點,添加到數組裏 
  7. ret.push(nodes[i]); 
  8. return ret; 

PS:上面的方法,採用的忽略空白文件節點的方法,把得到元素節點累加到數組裏返
回。那麼還有一種做法是,直接刪除空位文件節點即可。

  1. function filterSpaceNode(nodes) { 
  2. for (var i = 0; i < nodes.length; i ++) { 
  3. if (nodes[i].nodeType == 3 && /^\s+$/.test(nodes[i].nodeValue)) { 
  4. //得到空白節點之後,移到父節點上,刪除子節點 
  5. nodes[i].parentNode.removeChild(nodes[i]); 
  6. return nodes; 

PS:如果firstChild、lastChild、previousSibling 和nextSibling 在獲取節點的過程中遇到
空白節點,我們該怎麼處理掉呢?

  1. function removeWhiteNode(nodes) { 
  2. for (var i = 0; i < nodes.childNodes.length; i ++) { 
  3. if (nodes.childNodes[i].nodeType === 3 && 
  4. /^\s+$/.test(nodes.childNodes[i].nodeValue)) { 
  5. nodes.childNodes[i].parentNode.removeChild(nodes.childNodes[i]); 
  6. return nodes; 

四.節點操作
DOM 不單單可以查找節點,也可以創建節點、複製節點、插入節點、刪除節點和替換
節點。

1.write()方法
write()方法可以把任意字符串插入到文檔中去。

  1. document.write('<p>這是一個段落!</p>')'; //輸出任意字符串 

2.createElement()方法
createElement()方法可以創建一個元素節點。

  1. document.createElement('p'); //創建一個元素節點 

3.appendChild()方法
appendChild()方法講一個新節點添加到某個節點的子節點列表的末尾上。

  1. var box = document.getElementById('box'); //獲取某一個元素節點 
  2. var p = document.createElement('p'); //創建一個新元素節點<p> 
  3. box.appendChild(p); //把新元素節點<p>添加子節點末尾 

4.createTextNode()方法
createTextNode()方法創建一個文本節點。

  1. var text = document.createTextNode('段落'); //創建一個文本節點 
  2. p.appendChild(text); //將文本節點添加到子節點末尾 

5.insertBefore()方法
insertBefore()方法可以把節點創建到指定節點的前面。

  1. box.parentNode.insertBefore(p, box); //把<div>之前創建一個節點 

PS:insertBefore()方法可以給當前元素的前面創建一個節點,但卻沒有提供給當前元素
的後面創建一個節點。那麼,我們可以用已有的知識創建一個insertAfter()函數。

  1. function insertAfter(newElement, targetElement) { 
  2. //得到父節點 
  3. var parent = targetElement.parentNode; 
  4. //如果最後一個子節點是當前元素,那麼直接添加即可 
  5. if (parent.lastChild === targetElement) { 
  6. parent.appendChild(newElement); 
  7. else { 
  8. //否則,在當前節點的下一個節點之前添加 
  9. parent.insertBefore(newElement, targetElement.nextSibling); 

PS:createElement 在創建一般元素節點的時候,瀏覽器的兼容性都還比較好。但在幾
個特殊標籤上,比如iframe、input 中的radio 和checkbox、button 元素中,可能會在IE6,7
以下的瀏覽器存在一些不兼容。

  1. var input = null
  2. if (BrowserDetect.browser == 'Internet Explorer' && BrowserDetect.version <= 7) { 
  3. //判斷IE6,7,使用字符串的方式 
  4. input = document.createElement("<input type=\"radio\" name=\"sex\">"); 
  5. else { 
  6. //標準瀏覽器,使用標準方式 
  7. input = document.createElement('input'); 
  8. input.setAttribute('type''radio'); 
  9. input.setAttribute('name''sex'); 
  10. document.getElementsByTagName('body')[0].appendChild(input); 

6.repalceChild()方法
replaceChild()方法可以把節點替換成指定的節點。

  1. box.parentNode.replaceChild(p,box); //把<div>換成了<p> 

7.cloneNode()方法
cloneNode()方法可以把子節點複製出來。

  1. var box = document.getElementById('box'); 
  2. var clone = box.firstChild.cloneNode(true); //獲取第一個子節點,true 表示複製內容 
  3. box.appendChild(clone); //添加到子節點列表末尾 

8.removeChild()方法
removeChild()方法可以把

  1. box.parentNode.removeChild(box); //刪除指定節點 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章