[TOC]
## document節點概述
document節點是文檔的根節點,每張網頁都有自己的document節點。window.document屬性就指向這個節點。也就是說,只要瀏覽器開始載入HTML文檔,這個節點對象就開始存在了,可以直接調用。
document節點有不同的辦法可以獲取。
* 對于正常的網頁,直接使用document或window.document。
* 對于iframe載入的網頁,使用iframe節點的contentDocument屬性。
* 對Ajax操作返回的文檔,使用XMLHttpRequest對象的responseXML屬性。
* 對于某個節點包含的文檔,使用該節點的ownerDocument屬性。
上面這四種document節點,都部署了[Document接口](http://dom.spec.whatwg.org/#interface-document),因此有共同的屬性和方法。當然,各自也有一些自己獨特的屬性和方法,比如HTML和XML文檔的document節點就不一樣。
## document節點的屬性
document節點有很多屬性,用得比較多的是下面這些。
### doctype,documentElement,defaultView,body,head,activeElement
以下屬性指向文檔內部的某個節點。
(1)doctype
對于HTML文檔來說,document對象一般有兩個子節點。第一個子節點是document.doctype,它是一個對象,包含了當前文檔類型(Document Type Declaration,簡寫DTD)信息。對于HTML5文檔,該節點就代表。如果網頁沒有聲明DTD,該屬性返回null。
~~~
var doctype = document.doctype;
doctype // "<!DOCTYPE html>"
doctype.name // "html"
~~~
document.firstChild通常就返回這個節點。
(2)documentElement
document.documentElement屬性,表示當前文檔的根節點(root)。它通常是document節點的第二個子節點,緊跟在`document.doctype`節點后面。
對于HTML網頁,該屬性返回HTML節點,代表。
(3)defaultView
defaultView屬性,在瀏覽器中返回document對象所在的window對象,否則返回null。
~~~
var win = document.defaultView;
~~~
(4)body
body屬性返回當前文檔的body或frameset節點,如果不存在這樣的節點,就返回null。這個屬性是可寫的,如果對其寫入一個新的節點,會導致原有的所有子節點被移除。
(4)head
head屬性返回當前文檔的head節點。如果當前文檔有多個head,則返回第一個。
~~~
document.head === document.querySelector("head")
~~~
(5)activeElement
activeElement屬性返回當前文檔中獲得焦點的那個元素。用戶通常可以使用tab鍵移動焦點,使用空格鍵激活焦點,比如如果焦點在一個鏈接上,此時按一下空格鍵,就會跳轉到該鏈接。
### documentURI,URL,domain,lastModified,location,referrer,title,characterSet
以下屬性返回文檔信息。
(1)documentURI,URL
documentURI屬性和URL屬性都返回當前文檔的網址。不同之處是documentURI屬性是所有文檔都具備的,URL屬性則是HTML文檔獨有的。
(2)domain
domain屬性返回當前文檔的域名。比如,某張網頁的網址是?[http://www.example.com/hello.html](http://www.example.com/hello.html),domain屬性就等于?[www.example.com](http://www.example.com/)?。如果無法獲取域名,該屬性返回null。
~~~
var badDomain = "www.example.xxx";
if (document.domain === badDomain)
window.close();
~~~
上面代碼判斷,如果當前域名等于指定域名,則關閉窗口。
二級域名的情況下,domain屬性可以設置為對應的一級域名。比如,當前域名是sub.example.com,則domain屬性可以設置為example.com。除此之外的寫入,都是不可以的。
(3)lastModified
lastModified屬性返回當前文檔最后修改的時間戳,格式為字符串。
~~~
document.lastModified
// Tuesday, July 10, 2001 10:19:42
~~~
注意,lastModified屬性的值是字符串,所以不能用來直接比較,兩個文檔誰的日期更新,需要用Date.parse方法轉成時間戳格式,才能進行比較。
~~~
if (Date.parse(doc1.lastModified) > Date.parse(doc2.lastModified)) {
// ...
}
~~~
(4)location
location屬性返回一個只讀對象,提供了當前文檔的URL信息。
~~~
// 假定當前網址為http://user:passwd@www.example.com:4097/path/a.html?x=111#part1
document.location.href // "http://user:passwd@www.example.com:4097/path/a.html?x=111#part1"
document.location.protocol // "http:"
document.location.host // "www.example.com:4097"
document.location.hostname // "www.example.com"
document.location.port // "4097"
document.location.pathname // "/path/a.html"
document.location.search // "?x=111"
document.location.hash // "#part1"
document.location.user // "user"
document.location.password // "passed"
// 跳轉到另一個網址
document.location.assign('http://www.google.com')
// 優先從服務器重新加載
document.location.reload(true)
// 優先從本地緩存重新加載(默認值)
document.location.reload(false)
// 跳轉到另一個網址,但當前文檔不保留在history對象中,
// 即無法用后退按鈕,回到當前文檔
document.location.assign('http://www.google.com')
// 將location對象轉為字符串,等價于document.location.href
document.location.toString()
~~~
雖然location屬性返回的對象是只讀的,但是可以將URL賦值給這個屬性,網頁就會自動跳轉到指定網址。
~~~
document.location = 'http://www.example.com';
// 等價于
document.location.href = 'http://www.example.com';
~~~
document.location屬性與window.location屬性等價,歷史上,IE曾經不允許對document.location賦值,為了保險起見,建議優先使用window.location。如果只是單純地獲取當前網址,建議使用document.URL。
(5)referrer
referrer屬性返回一個字符串,表示前文檔的訪問來源,如果是無法獲取來源或是用戶直接鍵入網址,而不是從其他網頁點擊,則返回一個空字符串。
(6)title
title屬性返回當前文檔的標題,該屬性是可寫的。
~~~
document.title = '新標題';
~~~
(7)characterSet
characterSet屬性返回渲染當前文檔的字符集,比如UTF-8、ISO-8859-1。
### readyState,designModed
以下屬性與文檔行為有關。
(1)readyState
readyState屬性返回當前文檔的狀態,共有三種可能的值,加載HTML代碼階段(尚未完成解析)是“loading”,加載外部資源階段是“interactive”,全部加載完成是“complete”。
(2)designModed
designMode屬性控制當前document是否可編輯。通常會打開iframe的designMode屬性,將其變為一個所見即所得的編輯器。
~~~
iframe_node.contentDocument.designMode = "on";
~~~
### implementation,compatMode
以下屬性返回文檔的環境信息。
(1)implementation
implementation屬性返回一個對象,用來甄別當前環境部署了哪些DOM相關接口。implementation屬性的hasFeature方法,可以判斷當前環境是否部署了特定版本的特定接口。
~~~
document.implementation.hasFeature( 'HTML, 2.0 )
// true
document.implementation.hasFeature('MutationEvents','2.0')
// true
~~~
上面代碼表示,當前環境部署了DOM HTML 2.0版和MutationEvents的2.0版。
(2)compatMode
compatMode屬性返回瀏覽器處理文檔的模式,可能的值為BackCompat(向后兼容模式)和 CSS1Compat(嚴格模式)。
### anchors,embeds,forms,images,links,scripts,styleSheets
以下屬性返回文檔內部特定元素的集合(即HTMLCollection對象,詳見下文)。這些集合都是動態的,原節點有任何變化,立刻會反映在集合中。
(1)anchors
anchors屬性返回網頁中所有的a節點元素。注意,只有指定了name屬性的a元素,才會包含在anchors屬性之中。
(2)embeds
embeds屬性返回網頁中所有嵌入對象,即embed標簽,返回的格式為類似數組的對象(nodeList)。
(3)forms
forms屬性返回頁面中所有表單。
~~~
var selectForm = document.forms[index];
var selectFormElement = document.forms[index].elements[index];
~~~
上面代碼獲取指定表單的指定元素。
(4)images
images屬性返回頁面所有圖片元素(即img標簽)。
~~~
var ilist = document.images;
for(var i = 0; i < ilist.length; i++) {
if(ilist[i].src == "banner.gif") {
// ...
}
}
~~~
上面代碼在所有img標簽中,尋找特定圖片。
(4)links
links屬性返回當前文檔所有的鏈接元素(即a標簽,或者說具有href屬性的元素)。
(5)scripts
scripts屬性返回當前文檔的所有腳本(即script標簽)。
~~~
var scripts = document.scripts;
if (scripts.length !== 0 ) {
console.log("當前網頁有腳本");
}
~~~
(6)styleSheets
styleSheets屬性返回一個類似數組的對象,包含了當前網頁的所有樣式表。該屬性提供了樣式表操作的接口。然后,每張樣式表對象的cssRules屬性,返回該樣式表的所有CSS規則。這又方便了操作具體的CSS規則。
~~~
var allSheets = [].slice.call(document.styleSheets);
~~~
上面代碼中,使用slice方法將document.styleSheets轉為數組,以便于進一步處理。
### cookie
(1)概述
cookie屬性返回當前網頁的cookie。
~~~
// 讀取當前網頁的所有cookie
allCookies = document.cookie;
~~~
該屬性是可寫的,但是一次只能寫入一個cookie,也就是說寫入并不是覆蓋,而是添加。另外,cookie的值必須對分號、逗號和空格進行轉義。
~~~
// 寫入一個新cookie
document.cookie = "test1=hello";
// 再寫入一個cookie
document.cookie = "test2=world";
document.cookie
// test1=hello;test2=world
~~~
cookie屬性的讀寫操作含義不同,跟服務器與瀏覽器的通信格式有關。瀏覽器向服務器發送cookie,是一次性所有cookie全部發送。
~~~
GET /sample_page.html HTTP/1.1
Host: www.example.org
Cookie: cookie_name1=cookie_value1; cookie_name2=cookie_value2
Accept: */*
~~~
服務器告訴瀏覽器需要儲存cookie,則是分行指定。
~~~
HTTP/1.0 200 OK
Content-type: text/html
Set-Cookie: cookie_name1=cookie_value1
Set-Cookie: cookie_name2=cookie_value2; expires=Sun, 16 Jul 3567 06:23:41 GMT
~~~
cookie的值可以用encodeURIComponent方法進行處理,對逗號、分號、空格進行轉義(這些符號都不允許作為cookie的值)。
(2)cookie的屬性
除了cookie本身的內容,還有一些可選的屬性也是可以寫入的,它們都必須以分號開頭。
~~~
Set-Cookie: value[; expires=date][; domain=domain][; path=path][; secure]
~~~
* ; path=path,指定路徑,必須是絕對路徑(比如'/','/mydir'),如果未指定,默認為設定該cookie的路徑。只有path屬性匹配向服務器發送的路徑,cookie才會發送。這里的匹配不是絕對匹配,而是從根路徑開始,只要path屬性匹配發送路徑的一部分,就可以發送。比如,path屬性等于`/blog`,則發送路徑是`/blog`或者`/blogroll`,cookie都會發送。path屬性生效的前提是domain屬性匹配。
* ; domain=domain,指定cookie所在的域名,比如'example.com','.example.com'(這種寫法將對所有子域名生效)、'subdomain.example.com'。如果未指定,默認為設定該cookie的域名。所指定的域名必須是當前發送cookie的域名的一部分,比如當前訪問的域名是example.com,就不能將其設為google.com。只有訪問的域名匹配domain屬性,cookie才會發送到服務器。
* ; max-age=max-age-in-seconds,指定cookie有效期,比如60*60*24*365(即一年31536e3秒)。
* ; expires=date-in-GMTString-format,指定cookie過期時間,日期格式等同于Date.toUTCString()的格式。如果不設置該屬性,則cookie只在當前會話(session)有效,瀏覽器窗口一旦關閉,當前session結束,該cookie就會被刪除。瀏覽器根據本地時間,決定cookie是否過期,由于本地時間是不精確的,所以沒有辦法保證cookie一定會在服務器指定的時間過期。
* ; secure,指定cookie只能在加密協議HTTPS下發送到服務器。該屬性只是一個開關,不需要設定值。在HTTPS協議下設定的cookie,該開關自動打開。
以上屬性可以同時設置一個或多個,也沒有次序的要求。如果服務器想改變一個早先設置的cookie,必須同時滿足四個條件:cookie的名字、domain、path和secure。也就是說,如果原始的cookie是用如下的Set-Cookie頭命令設置的。
~~~
Set-Cookie: key1=value1; domain=example.com; path=/blog
~~~
改變上面這個cookie的值,就必須使用同樣的Set-Cookie命令。
~~~
Set-Cookie: key1=value2; domain=example.com; path=/blog
~~~
只要有一個屬性不同,就會生成一個全新的cookie,而不是替換掉原來那個cookie。
~~~
Set-Cookie: key1=value2; domain=example.com; path=/
~~~
上面的命令設置了一個全新的同名cookie。下一次訪問`example.com/blog`的時候,瀏覽器將向服務器發送兩個同名的cookie。
~~~
Cookie: key1=value1; key1=value2
~~~
上面代碼的兩個cookie是同名的,匹配越精確的cookie排在越前面。
~~~
var str = 'someCookieName=true';
str += '; expires=Fri, 31 Dec 9999 23:59:59 GMT';
str += '; path=/';
document.cookie = str;
~~~
另外,上面這些cookie屬性只能用來設置cookie。一旦設置完成,就沒有辦法從某個cookie讀取這些屬性的值。
刪除一個cookie的簡便方法,就是設置expires屬性等于0。
(3)cookie的限制
瀏覽器對cookie的數量和長度有限制,但是每個瀏覽器的規定是不一樣的。
* IE6:每個域名20個cookie。
* IE7,IE8,Firefox:每個域名50個cookie
* Safari,Chrome:沒有域名數量的限制。
所有cookie的累加長度限制為4KB。超過這個長度的cookie,將被忽略,不會被設置。
由于cookie存在數量限制,有時為了規避限制,可以將cookie設置成下面的形式。
~~~
name=a=b&c=d&e=f&g=h
~~~
上面代碼實際上是設置了一個cookie,但是這個cookie內部使用&符號,設置了多部分的內容。因此,可以在一個cookie里面,通過自行解析,可以得到多個鍵值對。這樣就規避了cookie的數量限制。
(4)HTTP-Only cookie
設置cookie的時候,如果服務器加上了HTTPOnly屬性,則這個cookie無法被JavaScript讀取(即`document.cookie`不會返回這個cookie的值),只用于向服務器發送。
~~~
Set-Cookie: key=value; HttpOnly
~~~
上面的這個cookie將無法用JavaScript獲取。進行AJAX操作時,getAllResponseHeaders方法或getResponseHeader方法也不會顯示這個頭命令。
## document對象的方法
document對象主要有以下一些方法。
### open(),close(),write(),writeln()
document.open方法用于新建一個文檔,供write方法寫入內容。它實際上等于清除當前文檔,重新寫入內容。不要將此方法與window.open()混淆,后者用來打開一個新窗口,與當前文檔無關。
document.close方法用于關閉open方法所新建的文檔。一旦關閉,write方法就無法寫入內容了。如果再調用write方法,就等同于又調用open方法,新建一個文檔,再寫入內容。
document.write方法用于向當前文檔寫入內容。只要當前文檔還沒有用close方法關閉,它所寫入的內容就會追加在已有內容的后面。
~~~
// 頁面顯示“helloworld”
document.open();
document.write("hello");
document.write("world");
document.close();
~~~
如果頁面已經渲染完成(DOMContentLoaded事件發生之后),再調用write方法,它會先調用open方法,擦除當前文檔所有內容,然后再寫入。
~~~
document.addEventListener("DOMContentLoaded", function(event) {
document.write('<p>Hello World!</p>');
});
// 等同于
document.addEventListener("DOMContentLoaded", function(event) {
document.open();
document.write('<p>Hello World!</p>');
document.close();
});
~~~
如果在頁面渲染過程中調用write方法,并不會調用open方法。(可以理解成,open方法已調用,但close方法還未調用。)
~~~
<html>
<body>
hello
<script type="text/javascript">
document.write("world")
</script>
</body>
</html>
~~~
在瀏覽器打開上面網頁,將會顯示“hello world”。
需要注意的是,雖然調用close方法之后,無法再用write方法寫入內容,但這時當前頁面的其他DOM節點還是會繼續加載。
~~~
<html>
<head>
<title>write example</title>
<script type="text/javascript">
document.open();
document.write("hello");
document.close();
</script>
</head>
<body>
world
</body>
</html>
~~~
在瀏覽器打開上面網頁,將會顯示“hello world”。
總之,除了某些特殊情況,應該盡量避免使用document.write這個方法。
document.writeln方法與write方法完全一致,除了會在輸出內容的尾部添加換行符。
~~~
document.write(1);
document.write(2);
// 12
document.writeln(1);
document.writeln(2);
// 1
// 2
//
~~~
注意,writeln方法添加的是ASCII碼的換行符,渲染成HTML網頁時不起作用。
### hasFocus()
document.hasFocus方法返回一個布爾值,表示當前文檔之中是否有元素被激活或獲得焦點。
~~~
focused = document.hasFocus();
~~~
注意,有焦點的文檔必定被激活(active),反之不成立,激活的文檔未必有焦點。比如如果用戶點擊按鈕,從當前窗口跳出一個新窗口,該新窗口就是激活的,但是不擁有焦點。
### querySelector(),getElementById(),querySelectorAll(),getElementsByTagName(),getElementsByClassName(),getElementsByName(),elementFromPoint()
以下方法用來選中當前文檔中的元素。
(1)querySelector()
querySelector方法返回匹配指定的CSS選擇器的元素節點。如果有多個節點滿足匹配條件,則返回第一個匹配的節點。如果沒有發現匹配的節點,則返回null。
~~~
var el1 = document.querySelector(".myclass");
var el2 = document.querySelector('#myParent > [ng-click]');
~~~
querySelector方法無法選中CSS偽元素。
(2)getElementById()
getElementById方法返回匹配指定ID屬性的元素節點。如果沒有發現匹配的節點,則返回null。
~~~
var elem = document.getElementById("para1");
~~~
注意,在搜索匹配節點時,ID屬性是大小寫敏感的。比如,如果某個節點的ID屬性是main,那么`document.getElementById("Main")`將返回null,而不是指定節點。
getElementById方法與querySelector方法都能獲取元素節點,不同之處是querySelector方法的參數使用CSS選擇器語法,getElementById方法的參數是HTML標簽元素的id屬性。
~~~
document.getElementById('myElement')
document.querySelector('#myElement')
~~~
上面代碼中,兩個方法都能選中id為myElement的元素,但是getElementById()比querySelector()效率高得多。
(3)querySelectorAll()
querySelectorAll方法返回匹配指定的CSS選擇器的所有節點,返回的是NodeList類型的對象。NodeList對象不是動態集合,所以元素節點的變化無法實時反映在返回結果中。
~~~
elementList = document.querySelectorAll(selectors);
~~~
querySelectorAll方法的參數,可以是逗號分隔的多個CSS選擇器,返回所有匹配其中一個選擇器的元素。
~~~
var matches = document.querySelectorAll("div.note, div.alert");
~~~
上面代碼返回class屬性是note或alert的div元素。
querySelectorAll方法支持復雜的CSS選擇器。
~~~
// 選中data-foo-bar屬性等于someval的元素
document.querySelectorAll('[data-foo-bar="someval"]');
// 選中myForm表單中所有不通過驗證的元素
document.querySelectorAll('#myForm :invalid');
// 選中div元素,那些class含ignore的除外
document.querySelectorAll('DIV:not(.ignore)');
// 同時選中div,a,script三類元素
document.querySelectorAll('DIV, A, SCRIPT');
~~~
如果querySelectorAll方法和getElementsByTagName方法的參數是字符串“*”,則會返回文檔中的所有HTML元素節點。
與querySelector方法一樣,querySelectorAll方法無法選中CSS偽元素。
(4)getElementsByClassName()
getElementsByClassName方法返回一個類似數組的對象(HTMLCollection類型的對象),包括了所有class名字符合指定條件的元素(搜索范圍包括本身),元素的變化實時反映在返回結果中。這個方法不僅可以在document對象上調用,也可以在任何元素節點上調用。
~~~
// document對象上調用
var elements = document.getElementsByClassName(names);
// 非document對象上調用
var elements = rootElement.getElementsByClassName(names);
~~~
getElementsByClassName方法的參數,可以是多個空格分隔的class名字,返回同時具有這些節點的元素。
~~~
document.getElementsByClassName('red test');
~~~
上面代碼返回class同時具有red和test的元素。
(5)getElementsByTagName()
getElementsByTagName方法返回所有指定標簽的元素(搜索范圍包括本身)。返回值是一個HTMLCollection對象,也就是說,搜索結果是一個動態集合,任何元素的變化都會實時反映在返回的集合中。這個方法不僅可以在document對象上調用,也可以在任何元素節點上調用。
~~~
var paras = document.getElementsByTagName("p");
~~~
上面代碼返回當前文檔的所有p元素節點。
注意,getElementsByTagName方法會將參數轉為小寫后,再進行搜索。
(6)getElementsByName()
getElementsByName方法用于選擇擁有name屬性的HTML元素,比如form、img、frame、embed和object,返回一個NodeList格式的對象,不會實時反映元素的變化。
~~~
// 假定有一個表單是<form name="x"></form>
var forms = document.getElementsByName("x");
forms[0].tagName // "FORM"
~~~
注意,在IE瀏覽器使用這個方法,會將沒有name屬性、但有同名id屬性的元素也返回,所以name和id屬性最好設為不一樣的值。
(7)elementFromPoint()
elementFromPoint方法返回位于頁面指定位置的元素。
~~~
var element = document.elementFromPoint(x, y);
~~~
上面代碼中,elementFromPoint方法的參數x和y,分別是相對于當前窗口左上角的橫坐標和縱坐標,單位是CSS像素。elementFromPoint方法返回位于這個位置的DOM元素,如果該元素不可返回(比如文本框的滾動條),則返回它的父元素(比如文本框)。如果坐標值無意義(比如負值),則返回null。
### createElement(),createTextNode(),createAttribute(),createDocumentFragment()
以下方法用于生成元素節點。
(1)createElement()
createElement方法用來生成HTML元素節點。
~~~
var element = document.createElement(tagName);
// 實例
var newDiv = document.createElement("div");
~~~
createElement方法的參數為元素的標簽名,即元素節點的tagName屬性。如果傳入大寫的標簽名,會被轉為小寫。如果參數帶有尖括號(即)或者是null,會報錯。
(2)createTextNode()
createTextNode方法用來生成文本節點,參數為所要生成的文本節點的內容。
~~~
var newDiv = document.createElement("div");
var newContent = document.createTextNode("Hello");
newDiv.appendChild(newContent);
~~~
上面代碼新建一個div節點和一個文本節點,然后將文本節點插入div節點。
(3)createAttribute()
createAttribute方法生成一個新的屬性對象節點,并返回它。
~~~
attribute = document.createAttribute(name);
~~~
createAttribute方法的參數name,是屬性的名稱。
~~~
var node = document.getElementById("div1");
var a = document.createAttribute("my_attrib");
a.value = "newVal";
node.setAttributeNode(a);
// 等同于
var node = document.getElementById("div1");
node.setAttribute("my_attrib", "newVal");
~~~
(4)createDocumentFragment()
createDocumentFragment方法生成一個DocumentFragment對象。
~~~
var docFragment = document.createDocumentFragment();
~~~
DocumentFragment對象是一個存在于內存的DOM片段,但是不屬于當前文檔,常常用來生成較復雜的DOM結構,然后插入當前文檔。這樣做的好處在于,因為DocumentFragment不屬于當前文檔,對它的任何改動,都不會引發網頁的重新渲染,比直接修改當前文檔的DOM有更好的性能表現。
~~~
var docfrag = document.createDocumentFragment();
[1, 2, 3, 4].forEach(function(e) {
var li = document.createElement("li");
li.textContent = e;
docfrag.appendChild(li);
});
document.body.appendChild(docfrag);
~~~
### createEvent()
createEvent方法生成一個事件對象,該對象可以被element.dispatchEvent方法使用,觸發指定事件。
~~~
var event = document.createEvent(type);
~~~
createEvent方法的參數是事件類型,比如UIEvents、MouseEvents、MutationEvents、HTMLEvents。
~~~
var event = document.createEvent('Event');
event.initEvent('build', true, true);
document.addEventListener('build', function (e) {
// ...
}, false);
document.dispatchEvent(event);
~~~
### createNodeIterator(),createTreeWalker()
以下方法用于遍歷元素節點。
(1)createNodeIterator()
createNodeIterator方法返回一個DOM的子節點遍歷器。
~~~
var nodeIterator = document.createNodeIterator(
document.body,
NodeFilter.SHOW_ELEMENT
);
~~~
上面代碼返回body元素的遍歷器。createNodeIterator方法的第一個參數為遍歷器的根節點,第二個參數為所要遍歷的節點類型,這里指定為元素節點。其他類型還有所有節點(NodeFilter.SHOW_ALL)、文本節點(NodeFilter.SHOW_TEXT)、評論節點(NodeFilter.SHOW_COMMENT)等。
所謂“遍歷器”,在這里指可以用nextNode方法和previousNode方法依次遍歷根節點的所有子節點。
~~~
var nodeIterator = document.createNodeIterator(document.body);
var pars = [];
var currentNode;
while (currentNode = nodeIterator.nextNode()) {
pars.push(currentNode);
}
~~~
上面代碼使用遍歷器的nextNode方法,將根節點的所有子節點,按照從頭部到尾部的順序,讀入一個數組。nextNode方法先返回遍歷器的內部指針所在的節點,然后會將指針移向下一個節點。所有成員遍歷完成后,返回null。previousNode方法則是先將指針移向上一個節點,然后返回該節點。
~~~
var nodeIterator = document.createNodeIterator(
document.body,
NodeFilter.SHOW_ELEMENT
);
var currentNode = nodeIterator.nextNode();
var previousNode = nodeIterator.previousNode();
currentNode === previousNode // true
~~~
上面代碼中,currentNode和previousNode都指向同一個的節點。
有一個需要注意的地方,遍歷器返回的第一個節點,總是根節點。
(2)createTreeWalker()
createTreeWalker方法返回一個DOM的子樹遍歷器。它與createNodeIterator方法的區別在于,后者只遍歷子節點,而它遍歷整個子樹。
createTreeWalker方法的第一個參數,是所要遍歷的根節點,第二個參數指定所要遍歷的節點類型。
~~~
var treeWalker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_ELEMENT
);
var nodeList = [];
while(treeWalker.nextNode()) nodeList.push(treeWalker.currentNode);
~~~
上面代碼遍歷body節點下屬的所有元素節點,將它們插入nodeList數組。
### adoptNode(),importNode()
以下方法用于獲取外部文檔的節點。
(1)adoptNode()
adoptNode方法將某個節點,從其原來所在的文檔移除,插入當前文檔,并返回插入后的新節點。
~~~
node = document.adoptNode(externalNode);
~~~
importNode方法從外部文檔拷貝指定節點,插入當前文檔。
~~~
var node = document.importNode(externalNode, deep);
~~~
(2)importNode()
importNode方法用于創造一個外部節點的拷貝,然后插入當前文檔。它的第一個參數是外部節點,第二個參數是一個布爾值,表示對外部節點是深拷貝還是淺拷貝,默認是淺拷貝(false)。雖然第二個參數是可選的,但是建議總是保留這個參數,并設為true。
另外一個需要注意的地方是,importNode方法只是拷貝外部節點,這時該節點的父節點是null。下一步還必須將這個節點插入當前文檔的DOM樹。
~~~
var iframe = document.getElementsByTagName("iframe")[0];
var oldNode = iframe.contentWindow.document.getElementById("myNode");
var newNode = document.importNode(oldNode, true);
document.getElementById("container").appendChild(newNode);
~~~
上面代碼從iframe窗口,拷貝一個指定節點myNode,插入當前文檔。
### addEventListener(),removeEventListener(),dispatchEvent()
以下三個方法與Document節點的事件相關。這些方法都繼承自EventTarget接口,詳細介紹參見《Event對象》章節的《EventTarget》部分。
~~~
// 添加事件監聽函數
document.addEventListener('click', listener, false);
// 移除事件監聽函數
document.removeEventListener('click', listener, false);
// 觸發事件
var event = new Event('click');
document.dispatchEvent(event);
~~~
- 第一章 導論
- 1.1 前言
- 1.2 為什么學習JavaScript?
- 1.3 JavaScript的歷史
- 第二章 基本語法
- 2.1 語法概述
- 2.2 數值
- 2.3 字符串
- 2.4 對象
- 2.5 數組
- 2.6 函數
- 2.7 運算符
- 2.8 數據類型轉換
- 2.9 錯誤處理機制
- 2.10 JavaScript 編程風格
- 第三章 標準庫
- 3.1 Object對象
- 3.2 Array 對象
- 3.3 包裝對象和Boolean對象
- 3.4 Number對象
- 3.5 String對象
- 3.6 Math對象
- 3.7 Date對象
- 3.8 RegExp對象
- 3.9 JSON對象
- 3.10 ArrayBuffer:類型化數組
- 第四章 面向對象編程
- 4.1 概述
- 4.2 封裝
- 4.3 繼承
- 4.4 模塊化編程
- 第五章 DOM
- 5.1 Node節點
- 5.2 document節點
- 5.3 Element對象
- 5.4 Text節點和DocumentFragment節點
- 5.5 Event對象
- 5.6 CSS操作
- 5.7 Mutation Observer
- 第六章 瀏覽器對象
- 6.1 瀏覽器的JavaScript引擎
- 6.2 定時器
- 6.3 window對象
- 6.4 history對象
- 6.5 Ajax
- 6.6 同域限制和window.postMessage方法
- 6.7 Web Storage:瀏覽器端數據儲存機制
- 6.8 IndexedDB:瀏覽器端數據庫
- 6.9 Web Notifications API
- 6.10 Performance API
- 6.11 移動設備API
- 第七章 HTML網頁的API
- 7.1 HTML網頁元素
- 7.2 Canvas API
- 7.3 SVG 圖像
- 7.4 表單
- 7.5 文件和二進制數據的操作
- 7.6 Web Worker
- 7.7 SSE:服務器發送事件
- 7.8 Page Visibility API
- 7.9 Fullscreen API:全屏操作
- 7.10 Web Speech
- 7.11 requestAnimationFrame
- 7.12 WebSocket
- 7.13 WebRTC
- 7.14 Web Components
- 第八章 開發工具
- 8.1 console對象
- 8.2 PhantomJS
- 8.3 Bower:客戶端庫管理工具
- 8.4 Grunt:任務自動管理工具
- 8.5 Gulp:任務自動管理工具
- 8.6 Browserify:瀏覽器加載Node.js模塊
- 8.7 RequireJS和AMD規范
- 8.8 Source Map
- 8.9 JavaScript 程序測試
- 第九章 JavaScript高級語法
- 9.1 Promise對象
- 9.2 有限狀態機
- 9.3 MVC框架與Backbone.js
- 9.4 嚴格模式
- 9.5 ECMAScript 6 介紹
- 附錄
- 10.1 JavaScript API列表
- 草稿一:函數庫
- 11.1 Underscore.js
- 11.2 Modernizr
- 11.3 Datejs
- 11.4 D3.js
- 11.5 設計模式
- 11.6 排序算法
- 草稿二:jQuery
- 12.1 jQuery概述
- 12.2 jQuery工具方法
- 12.3 jQuery插件開發
- 12.4 jQuery.Deferred對象
- 12.5 如何做到 jQuery-free?
- 草稿三:Node.js
- 13.1 Node.js 概述
- 13.2 CommonJS規范
- 13.3 package.json文件
- 13.4 npm模塊管理器
- 13.5 fs 模塊
- 13.6 Path模塊
- 13.7 process對象
- 13.8 Buffer對象
- 13.9 Events模塊
- 13.10 stream接口
- 13.11 Child Process模塊
- 13.12 Http模塊
- 13.13 assert 模塊
- 13.14 Cluster模塊
- 13.15 os模塊
- 13.16 Net模塊和DNS模塊
- 13.17 Express框架
- 13.18 Koa 框架