DOM

1、DOM簡介

D——document,沒有文檔,也就是沒有網頁,DOM就無從談起。javascript

當建立了一個網頁並把它加載到web瀏覽器中時,DOM就悄然而生。瀏覽器根據網頁文檔建立一個文檔對象。html

O——object,對象。java

對象有三種,node

一、用戶自定義對象web

二、內建對象,javascript中的對象,如Array,Math,Date等。chrome

三、宿主對象,由瀏覽器提供的對象,如window對象。數組

M——model,模型。瀏覽器

正如一個火車模型表明一列真正的火車,DOM表明被加載到瀏覽器窗口裏的當前網頁。瀏覽器爲咱們提供了當前網頁的模型,可經過javascript去讀寫它。app

因此DOM(Document Object Model),文檔對象模型,能夠簡單理解爲表明網頁文檔的一顆樹(模型)。dom

2、nodeName、nodeValue以及nodeType和innerHTML和value

DOM將網頁表示爲一顆樹,該樹的節點類型有多種。

元素節點——html標籤

文本節點——文本

屬性節點——屬性老是被包含在標籤裏,因此屬性節點老是被包含在元素節點當中。(元素節點(屬性節點,文本節點))

一般能夠經過開發者工具(如firebug)查看dom結構,可是要說明一點,開發者工具中的DOM並不完整,由於有些元素存在於DOM中,可是不會被開發者工具顯示。好比回車會被當作一個文本節點。

 

點我查看DOM中的空白符

一、nodeType

DOM本質就是一堆節點的集合,因爲包含不一樣類型的信息,因此就有不一樣類型的節點。接下來看nodeType。

元素節點,nodeType爲1

屬性節點,nodeType爲2

文本節點,nodeType爲3

文檔節點,nodeType爲9

Note:文檔節點並非根元素(html),由於註釋等內容能夠出如今根元素以外。因此在構造DOM樹時,根元素並不適合做爲根節點,因此就出現了文檔節點,而根節點做爲文檔節點的子節點。

複製代碼
<body>
<p id="p">段落</p>
<script type="text/javascript">
    var element=document.getElementById("p");
    var text=document.getElementById("p").firstChild;
    var property=document.getElementById("p").getAttributeNode("id");
    console.log("元素節點nodeType返回值"+element.nodeType);
    console.log("文本節點nodeType返回值"+text.nodeType);
    console.log("屬性節點nodeType返回值"+property.nodeType);
    console.log("文檔節點nodeType返回值"+document.nodeType);
</script>
</body> 
複製代碼

這裏我要重點說一下屬性節點。先上一張圖:

圖是w3schools教程中的,屬性節點(紅色框)的畫法是很特別的,我第一次看教程沒看懂爲何要這麼畫?難道其中有隱情?可是教程也都沒有說起。

可能不少人沒注意,我如今來講一下。

由於屬性節點其實是附屬於元素的,因此不被看作是元素的子節點,由於並無被當作是DOM的一部分。在屬性節點上調用parentNode,previousSibling和nextSibling都返回null。

複製代碼
<body>
<p id="p">段落</p>
<script type="text/javascript">
    var element=document.getElementById("p");
    console.log("<p>的子節點是  "+element.firstChild);
    var property=document.getElementById("p").getAttributeNode("id");
    console.log("屬性節點的parentNode  "+property.parentNode);
    console.log("屬性節點的左鄰節點  "+property.previousSibling);
    console.log("屬性節點的右鄰節點  "+property.nextSibling);
</script>
</body>    
複製代碼

因此w3schools的畫法也就能夠理解了,屬性節點不是子節點,因此「隨便」掛到元素節點上。

 nodeType屬性常常和if配合使用,確保不會在錯誤的節點類型上執行錯誤的操做。好比

複製代碼
<script type="text/javascript">
window.onload=function(){
    var mynode=document.getElementById("p");
    if(mynode.nodeType==1){
        mynode.setAttribute('title','段落');
        mynode.style.color="red";
    }
}
</script>
複製代碼

補充內容:

值——元素類型

1——元素節點,表示文檔中元素,元素節點是惟一可以擁有屬性的節點類型。元素和屬性的文本內容都是由文本節點來表示的。

2——屬性節點,表明元素的屬性。

3——文本節點,只包含文本內容,也能夠只包含空白。

4——CDATA段節點。

5——ENTITY REFERENCE實體引用節點。實體引用節點能夠被用於表示DOM樹中的一個實體引用。

6——ENTITY實體節點,表示文檔中已分析或未分析的實體。

7——PI(processing instruction)處理指令節點,

8——註釋節點,表示註釋的內容。

9——文檔節點(DOCUMENT),文檔樹的根節點。

10——DOCUMENT TYPE文檔類型節點。

11——DOCUMENT FRAGMENT文檔片斷節點,文檔片斷是"輕量級的"或"最小的"Document對象。

12——NOTATION記號節點表示了在DTD中聲明的記號。

w3c12種nodeType

二、nodeName

對於元素節點,nodeName就是標籤名。元素節點也能夠經過tagName獲取標籤名。【update 20170315】

對於文本節點,nodeName永遠是#text

對於屬性節點,nodeName是屬性名稱

對於文檔節點,nodeName永遠是#document

注意

nodeName是一個只讀屬性,不能進行設置。

nodeName所包含的XML元素的標籤名稱永遠是大寫的。

複製代碼
<body>
<p id="p">段落</p>
<script type="text/javascript">
    var element=document.getElementById("p");
    var text=document.getElementById("p").firstChild;
    var property=document.getElementById("p").getAttributeNode("id");
    console.log("元素節點nodeName返回值"+element.nodeName);/*元素節點返回標籤名P*/
    console.log("文本節點nodeName返回值"+text.nodeName);/*文本節點永遠返回#text*/
    console.log("屬性節點nodeName返回值"+property.nodeName);/*返回屬性名,這裏是id*/
    console.log("文檔節點nodeName返回值"+document.nodeName);
</script>
</body>    
</html>
複製代碼

三、nodeValue

對於元素節點,由於自己不直接包含文本,因此nodeValue是不可用的。

對於文本節點,nodeValue值爲文本值

對於屬性節點,nodeValue值爲屬性值

複製代碼
<body>
<p id="p">段落</p>
<script type="text/javascript">
    var element=document.getElementById("p");
    var text=document.getElementById("p").firstChild;
    var property=document.getElementById("p").getAttributeNode("id");
    console.log("元素節點nodeValue返回值"+element.nodeValue);
    console.log("文本節點nodeValue返回值"+text.nodeValue);
    console.log("屬性節點nodeValue返回值"+property.nodeValue);
    console.log("文檔節點nodeValue返回值"+document.nodeValue);
</script>
</body>    
</html>
複製代碼

下面是一個關於nodeType,nodeName和nodeValue的綜合demo。

  View Code

四、innerHTML

innerHTML只對元素節點有用,獲取元素節點內容,也就是元素節點包含的文本節點的值。其餘節點使用nodeValue。

複製代碼
<body> 
<p id="p">p標籤的內容</p>
<script>
var p=document.getElementById("p");
console.log(p.innerHTML);
console.log(p.firstChild);//p的第一個子節點是文本節點
console.log(p.firstChild.innerHTML);//無效
console.log(p.firstChild.nodeValue);//使用nodeValue進行訪問
</script>
</body> 
複製代碼

五、value

儘管innerHTML只對元素節點有用,但不是全部的元素節點都能使用innerHTML,好比像<input> 這樣的替換元素。

<label>姓名:<input type="text" value="lxy" /></label>
<script>
var oinput=document.getElementsByTagName("input")[0];
console.log("oinput.innerHTML   "+oinput.innerHTML);//沒有內容
console.log("oinput.value   "+oinput.value);//獲取input的value屬性
</script>

其實很好理解,由於input裏面不包含文本節點,因此用innerHTML獲取不到文本節點的值。可以使用value獲取其屬性值。

相似的,form裏的DOM元素(input select checkbox textarea radio)值獲取時都使用value。

textarea雖然能夠訪問innerHTML,可是獲取的是初始文檔中的值,當頁面的textarea中的值發生變化時,innerHTML不會及時更新。有興趣可本身寫demo測試。

3、HTML DOM 訪問節點

DOM的思想就是每一個節點都是對象,是對象咱們就能夠經過一些方法獲取它或者改變它的屬性等。

能夠經過多種方法來查找DOM元素:

a、使用getElementById()和getElementByTagName()和getElementsByClassName()方法

b、經過一個元素節點的parentNode、childNodes、children、firstChild和lastChild和previousSibling和nextSibling

c、經過document.documentElement和document.body

一、getElementById()和getElementsByTagName()和getElementsByClassName()和getElementsByName()

這四種方法會忽略文檔的結構。

getElementById()很少說。

getElementsByTagName()使用指定標籤名返回全部元素,這些元素是調用該方法的元素的後代。

getElementsByClassName()返回帶有指定類名的全部元素的節點列表。

getElementsByName()根據元素的name屬性返回全部元素的節點列表。(IE容錯能力較強,會獲得一個數組,其中包括id等於name值的。我還沒測試)

複製代碼
<body> 
<span class="class">span標籤內容</span>
<p class="class">p標籤的內容</p>
<script>
var aclass=document.getElementsByClassName("class");
for(var i=0;i<aclass.length;i++){
    console.log(aclass[i].innerHTML);
}
</script>
</body> 
複製代碼

還有一些方法是和文檔結構相關的,由於DOM樹中的節點是緊密相連的

上——parentNode

下——childNodes/children,firstChild,lastChild

左/右——previousSibling/nextSibling

二、childNodes

 childNodes保存子節點的引用,包括空白也在內(除了IE<9),也包括<script>在內。

複製代碼
<!DOCTYPE HTML>
<!-- My document -->
<html>
<head>
  <title>My Document</title>
</head>
<body>
  <h1>Header</h1>
  <p>
    Paragraph
  </p>
  <script type="text/javascript">
  window.onload=function(){
      var childNodes=document.body.childNodes;
      for(var i=0;i<childNodes.length;i++){
          console.log(childNodes[i]);
      }
  }
  </script>
</body>
</html>
複製代碼

在chrome中效果以下,

三、children

若是隻想得到子節點中的元素節點,跳過文本節點,應該使用children屬性。

IE<9會在children屬性中列出註釋節點。

仍是上面的例子,將document.body.childNodes改成document.body.children;效果以下:

使用childNodes和children得到是一個集合,想要得到單個元素,可使用一些快速的索引siblings、parent等。

四、firstChild和lastChild

firstChild和lastChild是childNodes中首尾節點的快速索引。

var body=document.body;
alert(body.firstChild===body.childNodes[0]);//true
alert(body.lastChild===body.childNodes[body.childNodes.length-1]);//true

對firstChild最普通的用法是訪問某個元素節點的文本:

var x=[a paragraph];
var text=x.firstChild.nodeValue; 

小技能

寫代碼檢查DOM節點是否爲空,就是說沒有children或者文本。可用如下三種方法」

if (elem.childNodes.length) { ... }
if (elem.firstChild) { ... }
if (elem.lastChild) { ... }//最快

五、parentNode,previousSibling和nextSibling

獲取父節點或者左右相鄰的節點。

可藉助這些屬性來更新DOM,增刪元素。

parentNode屬性常被用來改變文檔的結構。假設但願從文檔中刪除帶有id爲"maindiv"的節點:

var x=document.getElementById("maindiv");
x.parentNode.removeChild(x); 

首先找到帶有指定id的節點,再移至其父節點並執行removeChidld()方法。

如今有一個問題:

document.body.lastChild.nextSibling老是null嗎?//是

一樣document.body.children[0].previousSibling呢?//不必定,null或者文本。由於document.body.children[0]表明第一個元素節點,可能會有文本節點做爲它 previousSibling。

六、特殊入口

 訪問DOM還有兩個特別的入口——document.documentElement和document.body。

document.documentElement表明<html>元素。

document.body表明<body>元素,能夠爲null,好比在body沒有呈現的時候引用就是null。

<head>
    <script type="text/javascript">
    alert("head部分的body"+document.body);/*null*/
    </script>
</head>

4、HTML DOM 操做

一、建立新元素(節點)

  • createElement()//建立一具體的元素
  • createTextNode()//建立一個文本節點
  • createDocumentFragment()//建立一個DOM片斷

createDocumentFragment()建立一個文檔碎片,把全部的節點都加在上面,最後把文檔碎片一次性添加到document中,比一次次修改DOM更高效。

查看createDocumentFragment()執行效率瞭解更多。

二、元素操做

a、更改元素內容

複製代碼
<body> 
<p id="p">p標籤的內容</p>
<script>
var p=document.getElementById("p");
alert("暫停觀察");
p.innerHTML="內容替換了";
</script>
</body> 
複製代碼

還能夠直接給文本節點的nodeValue賦值。

好比:p.firstChild.nodeValue="再次更新文字"

b、新增元素(appendChild和insertBefore)

appendChild()將新元素做爲父元素的最後一個子元素。

複製代碼
<body> 
<p id="p1">p標籤的內容</p>
<script>
var p1=document.getElementById("p1");
var newP=document.createElement("p");
var text=document.createTextNode("新增的p標籤的內容");
newP.appendChild(text);
p1.parentNode.appendChild(newP);
</script>
</body> 
複製代碼

insertBefore()經過父元素調用,將第一個元素插入第二個元素前面

複製代碼
<body> 
<p id="p1">p標籤的內容</p>
<script>
var p1=document.getElementById("p1");
var newP=document.createElement("p");
var text=document.createTextNode("新增的p標籤的內容");
newP.appendChild(text);
p1.parentNode.insertBefore(newP,p1);//經過父p1的父元素將newP插入到p1的前面
</script>
</body> 
複製代碼

c、移除元素removeChild

DOM中刪除元素,必須經過父元素進行操做。

複製代碼
<body> 
<p id="p1">p標籤的內容</p>
<script>
var p1=document.getElementById("p1");
alert("暫停觀察");
p1.parentNode.removeChild(p1);
</script>
</body> 
複製代碼

d、替換元素replaceChild

替換元素也必須經過父元素來進行,接收2個參數,和insertBefore相似,用第一個參數替換第二個。

複製代碼
<body> 
<p id="p1">p標籤的內容</p>
<script>
var p1=document.getElementById("p1");
var p2=document.createElement("p");
var text=document.createTextNode("替換的文本");
p2.appendChild(text);

alert("暫停觀察");
p1.parentNode.replaceChild(p2,p1);
</script>
</body> 
複製代碼

可見DOM結構的改動(增刪改)都是經過父節點來進行的。

e、一個綜合demo

經過InnerHTML更改元素內容,經過appendChild新增元素,經過removeChild移除元素。

複製代碼
<body> 
<input type="text" id="text"/>
<input type="button" value="添加li" id="button">
<ul>
</ul>
<script>
window.onload=function(){
    var obutton=document.getElementById("button");
    obutton.onclick=createLi;
}
function createLi(){
    var oText=document.getElementById("text");
    var oUl=document.getElementsByTagName("ul")[0];
    var oLi=document.createElement("li");
    oLi.innerHTML=oText.value;
    var oA=document.createElement("a");
    oA.innerHTML="刪除";
    oA.href="javascript:;";
    oA.onclick=function(){
        oUl.removeChild(this.parentNode);
    }
    oLi.appendChild(oA);
    oUl.appendChild(oLi);
}
</script>
</body> 
複製代碼

三、特性操做

用getAttribute(),setAttribute()和removeAttribute()控制HTML標籤的特性 。

複製代碼
<body>
    <a href="#">starof</a>
<script type="text/javascript">
        var a=document.getElementsByTagName("a")[0];  
        alert(a.getAttribute("href"));
        a.setAttribute("href","http://www.cnblogs.com/starof");
        alert(a.getAttribute("href"));
        a.removeAttribute("href");
        alert(a.getAttribute("href"));
</script>
</body>
複製代碼

經過setAttribute更改樣式:(就是重置內聯樣式)

不是p1.setAttribute("color","green");

而是p1.setAttribute("style","color:green;");

由於setAttribute的修改是動態的,因此查看源代碼時看不到!

四、樣式操做

obj.style.屬性=屬性值,是經過添加內聯樣式去覆蓋已有樣式的。

修改文字顏色爲紅色

複製代碼
<body> 
<p id="p">p標籤的內容</p>
<script>
var p=document.getElementById("p");
alert("暫停觀察");
p.style.color="red";
</script>
</body> 
複製代碼

 

五、事件操做

 DOM對HTML事件作響應。

事件處理的工做機制:

在元素添加了事件處理函數後,一旦預約事件發生,相應的JavaScript代碼能夠返回一個結果,而這個結果將被傳遞迴那個事件處理函數。

好比給某個連接添加一個onclick事件處理函數,並讓這個處理函數所觸發的JavaScript代碼返回布爾值true或false。這樣一來,當這個連接被點擊時,若是那段JavaScript返回給onclick事件處理函數的值是true,onclick事件處理函數將認爲「這個連接被點擊了」;反之若是那段JavaScript代碼返回給onclick事件處理函數的值是false,onclick事件處理函數將認爲「這個函數沒有被點擊」。

能夠拿下面代碼驗證:

<a href="http://www.baidu.com" onclick="return false;">click me</a>

關於事件這部份內容太多,有興趣可看

javaScript事件(一)事件流

javaScript事件(二)事件處理程序

javaScript事件(三)事件對象

javaScript事件(四)event的公共成員(屬性和方法)

javaScript事件(五)事件類型之鼠標事件

5、資源連接

javascript教程

DOM中的空白符

w3c12種nodeType

相關文章
相關標籤/搜索