除了IE(該死的IE),其餘全部瀏覽器均可以訪問到Node類型,而JS中全部節點類型都繼承自Node類型,所以全部節點類型都共享着相同的基本屬性和方法.
每一個節點都有一個nodeType
屬性,能夠代表節點的類型,咱們來看看有哪些類型吧javascript
Node.ELEMENT_NODE(1)
css
Node.ATTRIBUTE_NODE(2)
html
Node.TEXT_NODE(3)
java
Node.CDATA_SECTION_NODE(4)
node
Node.ENTITY_REFERENCE_NODE(5)
chrome
Node.ENTITY_NODE(6)
編程
Node.PROCESSING_INSTRUCTION_NODE(7)
跨域
Node.COMMENT_NODE(8)
數組
Node.DOCUMENT_NODE(9)
瀏覽器
Node.DOCUMENT_TYPE_NODE(10)
Node.DOCUMENT_FRAGMENT_NODE(11)
Node.NOTATION_NODE(12)
nodeName
和nodeValue
屬性則徹底取決於nodeType
,對於元素節點,nodeName
保存的始終爲標籤名,而nodeValue
保存的值始終爲null
childNodes
屬性中保存着一個NodeList
對象(類數組對象,並非Array的實例),NodeList
是動態的,是基於DOM結構動態執行查詢的結果,咱們能經過如下方式來訪問子節點.
var firstChild = someNode.childNodes[0]; var secondChild = someNode.childNodes.item(1); var count = someNode.childNodes.length;
對於NodeList
對象,咱們還能夠轉換爲數組,以下
var arrayOfNodes = Array.prototype.slice.call(someNode.childNodes,0);
值得注意,該段代碼在IE8及更早版本前是報錯的,這是由於IE8及更早版本將NodeList
實現爲一個COM對象,而咱們不能像使用JScript對象那樣使用該對象,因此上述代碼會致使錯誤.如下是對於兼容性的解決方法.
function convertToArray(nodes){ var array = null; try{ array = Array.prototype.slice.call(nodes,0);//非IE }catch(ex){ array = new Array(); for(var i = 0,len = nodes.length;i < len;i++){ array.push(node[i]); } } return array; }
每一個節點還有parentNode
屬性,該屬性指向文檔樹中的父節點.包含在childNodes列表中的全部節點都有相同的父節點,而childNodes列表中的每一個節點之間爲同胞節點,能夠經過previousSibling
和nextSibling
屬性訪問.若是列表只有一個節點,則該節點上述兩個屬性爲null
.
父節點與其第一個和最後一個子節點之間也存在特殊關係.父節點存在屬性firstChild
和lastChild
分別指向它們.其中firstChild
與childNodes[0]
相等,而x.lastChild
與x.childNodes[x.childNodes.length-1]
相等.
節點中hasChildNodes()
方法也是一個有用的方法,在包含節點狀況下返回true,不然返回false.
全部節點最後一個屬性都爲ownerDocument
,它指向表示整個文檔的文檔節點,即#document,可使咱們直接到達頂層.
注意:關係指針都是隻讀的,因此DOM提供了一些函數供咱們操做節點.
如下介紹了四種操做方法,都須要先取得父節點,可是須要明白不是全部類型的節點都有/支持子節點.
appendChild(node) //向childNodes列表末尾添加一個節點,並在添加後,關係指針會相應更新.
值得注意的是appendChild()添加的節點若是已是文檔的一部分,那麼至關於轉移節點.
insertBefore(node,null) //參數一爲插入節點,第二個參數則爲參照節點,設爲null則效果與appendChild同樣,存在參照節點則插入節點變成參照節點前一個同胞節點(previousSibling)
removeChild(oldNode) //移除並不是替換節點,返回值爲oldNode replaceChild(newNode,oldNode) //oldNode替換爲newNode,oldNode雖然技術上仍然存在,可是文檔中沒有了它的位置
這裏有兩個方法是全部類型節點都有的,它們就是cloneNode(boolean)
和normalize()
,咱們重點介紹cloneNode()
cloneNode(boolean) //傳入一個布爾值,該值決定執行深複製(節點及整個節點樹)仍是淺複製(僅複製自己)
注意點一:深複製IE9以前版本不會爲空白符建立節點,因此深複製時childNodes長度會有所不一樣.
注意點二:cloneNode()方法只複製特性和子節點(指定狀況下),不會複製JS屬性如事件處理程序等等(除開IE,存在複製事件處理程序的bug),因此複製前最好先移除事件處理程序.
除了Document類型,咱們Web編程中最經常使用的類型就是Element類型啦.
Element 類型用於表現XML或HTML元素,提供了對元素標籤名,子節點,特性的訪問
nodeType值爲1
nodeName爲元素標籤名
nodeValue爲null
parentNode多是Document或Element
子節點多是Element,Text,Comment,ProcessingInstruction,CDATASection,EntityReference
其中nodeName和tagName屬性返回相同的值,推薦使用tagName,則表義更清晰,值得注意的是返回值大小寫的問題,因爲HTML中爲答謝,而XML/XHTML則會與源代碼保持一致,因此比較時要統一大小寫形式.
<!-- more -->
HTML元素都由HTMLElement類型表示,不直接經過該類型,也是經過它的子類型表示.HTMLElement類型繼承自Element而且添加了一些屬性以下:
id 元素在文檔中的惟一標識符
title 元素的附加說明信息,通常爲工具提示條顯示
lang 元素內容的語言代碼,不多使用
dir 語言方向,ltr爲從左到右,rtl則相反
className 與元素class的特性對應,沒有設置爲class則是由於class爲ECMAScript的保留字
注意以上屬性的修改並非全部都會在頁面中直觀的表現出來,id和lang修改對用戶來講是不可見的(假設沒有css樣式),對title的修改則只會在鼠標移動到元素上時纔會顯示出來(工具提示條),dir的修改則會在屬性重寫的那一刻馬上影響頁面中的文本,對className的修改則與是否關聯了不一樣的CSS樣式有關.
HTML元素每一個元素都有一個或多個特性,操做特性的DOM方法以下有三個:
getAttribute()
setAttribute()
removeAttribute()
這三個方法能夠針對任何特性使用,包括自定義特性.
可是隻有公認的特性纔會添加到DOM元素屬性上,自定義的特性一般是不存在的(undefined),固然這裏又要注意咱們的"好朋友"IE啦,它會爲自定義特性建立屬性.
主要針對getAttribute()
方法講述一下特殊狀況.
有兩類特殊特性,有對應的屬性名,但值與getAttribute()
返回的值並不相同
style,經過getAttribute()
訪問會返回CSS文本,而經過屬性訪問返回一個對象
onclick這樣的事件處理程序,經過getAttribute()
訪問會返回相應代碼的字符串.而屬性訪問時,則會返回一個JavaScript函數(未指定則爲null)
故一般只有取得自定義特性值的狀況下,纔會使用getAttribute()
方法.
注意!:咱們的"老朋友"IE7及之前版本中,getAttribute()
方法訪問上述兩個特殊特性時,返回的值與屬性的值相同.即getAttribute("style")
返回一個對象,getAttribute("onclick")
返回一個函數.
這裏主要講解下setAttribute()
方法,這和getAttribute()
相對應.這個方法接受兩個參數,要設置的特性名和值,若是特性存在則將值進行替換;不存在則建立並設置相應的值.
值得注意的是,設置特性名會轉換爲小寫.並且直接給DOM元素添加一個自定義的屬性並不會讓這個屬性成爲元素的特性.
div.mycolor="red"; div.getAttribute("mycolor"); //這裏返回null(IE除外)
removeAttribute()
方法用於完全刪除元素特性,調用該方法會清除特性的值並徹底刪除特性.
注意!:IE6及之前版本不支持該方法.
Element類型是使用attributes屬性的惟一一個DOM節點類型.在該屬性中包含一個NamedNodeMap,與NodeList相似,也是"動態"集合.元素每個特性都由一個Attr節點表示,每一個節點都保存在NamedNodeMap對象中.相關方法以下:
getNamedItem(name)
返回nodeName屬性等於name的節點
removeNamedItem(name)
從列表移除nodeName等於name的節點
setNamedItem(node)
向列表添加節點,以節點的nodeName屬性爲索引
item(pos)
返回處於數字pos位置處的節點
在該屬性中有一系列的節點,每一個節點的nodeName就是特性的名稱,nodeValue就是特性的值.要取得元素的id特性,可使用attributes.getNamedItem("id").nodeValue
等同於attributes["id"].nodeValue
調用removeNamedItem()
與在元素上調用removeAttribute()
效果相同.
setNamedItem()
是一個很不經常使用的方法,該方法能夠爲元素添加一個新特性,此外須要爲它傳入一個特性節點.
注意!:IE7及更早版本會返回HTML元素中全部可能的特性,包括沒指定的特性.
針對低版本改進:每一個特性節點都有一個名爲specified的屬性,若是爲true則意味着要麼HTML中指定了相應特性,要麼經過setAttribute()
設置了該特性,在IE中未設置過的特性都爲false,其餘瀏覽器則不會爲這類特性生成對應特性節點.
document.createElement()
方法就可建立新元素.
該方法接受一個參數,就是元素標籤名,這個標籤名在HTML下不區分大小寫,XML中則會區分大小寫.
在建立新元素的同時,新元素也設置了ownerDocument屬性,此時,還能夠操做元素特性,爲它添加更多的子節點.
在設置完特性後,因爲未添加到文檔樹,因此一切特性都不會影響瀏覽器的顯示.咱們能夠經過以前講到的appendChild()
,insertBefore()
,replaceChild()
方法來進行相應的操做.
一旦添加到文檔樹,則瀏覽器會馬上呈現該元素.此後咱們的修改都會反應到瀏覽器中.
注意!(常不考慮):在IE中咱們能夠經過另外一種方式進行建立
document.createElement("<div id=\"myNewDiv\" class=\"box\"></div>");
這個方式能夠避開IE7及更早版本中動態建立元素的某些問題.(不能設置動態建立的iframe元素的name特性;不能經過表單的reset()方法重設動態建立的input元素;動態建立的type特性值爲"reset"的button元素重設不了表單;動態建立的一批name相同的單選按鈕彼此毫無關係)
元素子節點
除了IE,其餘瀏覽器解析代碼時會解析空白符爲文本節點.咱們能夠經過nodeType屬性的檢查來過濾掉它們.
在JavaScript中Document類型表示文檔,咱們經常使用的document對象是HTMLDocument(繼承自Document類型)的一個實例,表示整個HTML頁面;document對象仍是window對象的一個屬性,所以能夠將其做爲全局對象來訪問.
nodeType值爲9
nodeName爲"#document"
nodeValue爲null
parentNode爲null
ownerDocument爲null
子節點多是一個DocumentType(最多一個),Element(最多一個),ProcessingInstruction或Comment
Document類型能夠表示HTML頁面或者其餘基於XML的文檔,不過最多見的應用仍是做爲HTMLDocument實例的document對象.經過該對象,咱們能夠獲取頁面有關信息,操做頁面的外觀,以及其底層結構.
<!-- more -->
雖然DOM標準規定Document節點的子節點能夠是DocumentType,Element,ProcessingInstruction或Comment,可是還有兩個內置的訪問其子節點的快捷方式.
一:documentElement
屬性-始終指向HTML頁面中的<html>
元素
二:childNodes
列表
而且以下代碼所示
//html部分 //<html> // <body></body> //</html> var html = document.documentElement; console.log(html === document.childNodes[0]); //true console.log(html === document.firstChild); //true
可見documentElement
,firstChild
,childNodes[0]
指向同一個元素<html>
而且做爲HTMLDocument的實例,還有一個body
屬性,直接指向<body>
元素.
全部瀏覽器都支持document.documentElement
和document.body
屬性
<!DOCTYPE>
節點能夠經過document.doctype屬性獲取並訪問它的信息.
如下是各瀏覽器支持差異:
IE8及以前:存在文檔類型聲明,會錯誤解釋爲一個註釋並把它看成Comment節點;而document.doctype 值始終爲null
IE9+及firefox:若是存在文檔類型聲明,則會將其做爲文檔第一個子節點;document.doctype是一個DocumentType節點,也能夠經過document.firstChild或document.childNodes[0]訪問.
Safari,Chrome和Opera:若是存在文檔類型聲明,則會將其解析,但不做爲文檔子節點,document.doctype是一個DocumentType節點,但該節點不存在於document.childNodes中.
<!-- 註釋1 --> <html> <body> </body> </html> <!-- 註釋2 -->
對於上述註釋也在不一樣瀏覽器中存在不一樣.
IE8及以前,Safari3.1及更高,Opera和chrome:只爲第一條註釋建立節點,部位第二條註釋建立節點.
IE9+:將第一條註釋建立爲document.childNodes中的一個註釋節點,也將第二條註釋建立爲document.childNodes中的註釋子節點
Safari3.1以前,firefox:徹底忽略
以上的不一致性致使了不管是註釋仍是DocumentType節點對於咱們來講用處十分有限.
document對象有屬性提供了document對象所表現的網頁的一些信息.
title:包含在<title>
元素中的文本(瀏覽器窗口的標題欄或標籤頁上),可是修改該值不會改變<title>
元素.
URL:包含頁面完整的URL
domain:包含頁面的域名
referrer:保存連接到當前頁面的那個頁面的URL,如無來源頁面則爲空字符串.
注意!:這些信息都存在於HTTP頭部,只不過咱們能經過該屬性在JS中訪問它們.並且咱們只能在遵照規則(不能將這個屬性設置爲URL中不包含的域,不能將域縮緊如將wrox.com設置爲p2p.wrox.com同樣(IE8及以後))的狀況下設置domain屬性.
其中domain屬性仍是越過跨域安全限制的好辦法.
主要用到document對象如下方法.
getElementById("id") //接受一個參數,若是找到相應元素則返回該元素,不存在則返回null //注意!:IE8及較低版本不區分ID大小寫/若是存在多個ID則只返回第一次出現的/IE7及較低版本中name值與ID匹配的表單元素會被返回 getElementsByTagName("img") //接受一個參數,爲要取得元素的標籤名,返回一個NodeList(包含零或多個元素).在HTML文檔中,這個方法返回一個HTMLCollection對象,該對象與NodeList很是相似 getElementsByName("name") //只有HTMLDocument類型纔有的方法.和上述兩個方法類似,也就不解釋傳入參數之類的啦
元素數量能夠經過length
得到,並且咱們能夠經過.item()
和方括號語法[0]/["name特性"]
來訪問元素.namedItem()
方法則能夠經過name特性取得其中的元素.
除了屬性和方法,document對象還有一些特殊集合.這些集合都是HTMLCollection對象,爲訪問文檔經常使用部分提供了快捷方式,以下:
document.anchors
包含文檔中全部帶name特性的<a>
元素
document.applets
包含文檔中全部的<applet>
元素(已再也不推薦使用)
document.forms
包含文檔中全部<form>
元素
document.images
包含文檔中全部<img>
元素
document.links
包含文檔中全部帶href
特性的<a>
元素
該集合始終能夠經過HTMLDocument對象訪問到.並且是動態的隨着當前文檔內容的更新而更新.
document.implementation
屬性就是用在檢測瀏覽器實現了DOM的哪些部分.document.implementation.hasFeature()
方法接受兩個參數,要檢測的DOM功能名稱和版本號,若是瀏覽器支持則返回true.可是這並不表明着實現與規範一致
document對象有一個存在好久的功能,將輸出流寫入到網頁中的能力.這關乎到下列4個方法.
write()
writeln()
上面兩個方法都是接受一個字符串參數,writeln()額外在字符串寫入後再寫入一個換行符
注意!:若是要用於寫入<script></script>
則要對</script>
進行轉義=></script>
,防止script標籤被提早閉合致使沒法執行;若是在文檔接在結束後再調用則會致使整個頁面重寫.
open()
close()上述兩個方法用於打開和關閉網頁的輸出流,若是在頁面加載期間使用write()和writeln()則不須要用到這兩個方法(嚴格型的XHTML文檔不支持文檔寫入)