Document 對象時通往DOM功能的入口,它向你提供了當前文檔的信息,以及一組可供探索、導航、搜索或操做結構與內容的功能。html
咱們經過全局變量document訪問Document對象,它是瀏覽器爲咱們建立的關鍵對象之一。Document對象提供了文檔的總體信息,並讓你可以訪問模型裏的各個對象。簡單示例以下:node
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Example</title>
</head>
<body>
<p id="first">
15歲的時候再獲得那個5歲的時候熱愛的布娃娃,65歲的時候終於有錢買25歲的時候熱愛的那條裙子,又有什麼意義。
什麼均可以從頭再來,只有青春不能。那麼多事情,跟青春綁在一塊兒就是美好,離開青春,就是傻冒。
</p>
<p id="second"> 你的特別不是由於你在創業,不是由於你進了牛企,不是由於你的牛offer,而是由於你就是你,堅信本身的特別,堅信本身的心裏,勇敢作本身。 IT DOESN'T MATTER WHERE YOU ARE, IT MATTERS WHO YOU ARE. </p> <script> document.writeln("<pre>URL: "+document.URL); var elems = document.getElementsByTagName("p"); for(var i=0; i<elems.length; i++){ document.writeln("Element ID: "+elems[i].id); elems[i].style.border = "medium double black"; elems[i].style.padding = "4px"; } document.write("</pre>"); </script> </body> </html>
咱們能對Document對象作的最基本操做之一就是獲取當前正在處理的HTML文檔信息。這就是腳本的第一行所作的:git
document.writeln("<pre>URL: "+document.URL);
此例中,讀取了 document.URL 屬性的值,它返回的是當前文檔的URL。瀏覽器就是用這個URL載入此腳本所屬文檔的。github
這句語句還調用了writeln方法:數組
document.writeln("<pre>URL: "+document.URL);
此方法會將內容附加到HTML文檔的末尾。此例中,寫入了pre元素的開始標籤和URL屬性的值。這就是一個很是簡單的修改DOM範例,意思是我已經改變了文檔的結構。瀏覽器
接下來,從文檔中選擇了一些元素:cookie
var elems = document.getElementsByTagName("p");
getElementsByTagName 選擇屬於某一給定類型的全部元素,此例中是p元素。任何包含在文檔裏的p元素都會被該方法返回,並被存放在一個elems的變量裏。全部元素都是由HTMLElement對象表明的,它提供了基本的功能以表明HTML元素。getElementsByTagName方法返回的結果是HTMLElement對象所組成的一個集合。app
有了能夠處理的HTMLElement對象集合以後,使用了一個for循環來列舉集合裏的內容,處理瀏覽器從HTML文檔裏找出的各個p元素:less
for(var i=0; i<elems.length; i++){
document.writeln("Element ID: "+elems[i].id); elems[i].style.border = "medium double black"; elems[i].style.padding = "4px"; }
對集合裏的每一個HTMLElement,會讀取它的id屬性來獲取id 值,然使用 document.writeln 方法吧結果附加到以前生成的pre元素的內容上:ide
for(var i=0; i<elems.length; i++){
document.writeln("Element ID: "+elems[i].id); elems[i].style.border = "medium double black"; elems[i].style.padding = "4px"; }
id屬性是HTMLElement定義的衆多屬性之一。你可使用這些屬性來獲取某個元素的信息,也能夠對其進行修改(改動會同時應用到它所表明的HTML元素上)。此例中,使用了style屬性來改變CSS border和padding 屬性的值:
for(var i=0; i<elems.length; i++){
document.writeln("Element ID: "+elems[i].id); elems[i].style.border = "medium double black"; elems[i].style.padding = "4px"; }
這些改動爲每一個圓度都建立了一個內嵌樣式,這些元素都是以前用getElementsByTagName 方法找到的。當修改某個對象時,瀏覽器會當即把改動應用到對應的元素上,此例中是給這些p元素添加內邊距和邊框。
腳本的最後一行寫入了pre元素的結束標籤,就是在腳本開頭初始化的那個元素。這裏用的是write方法,但不會給添加到文檔裏的字符串附上行結束字符。這兩種方法區別不大,除非編寫的內容是預格式化的,或者使用非標準的空白處理方式。
使用pre元素就意思味着writeln方法所添加的行結束符字符會被用來構建內容。從下面的顯示效果圖能夠看到文檔排列的效果:
1. 使用 Document 元數據
下表介紹了能夠用來獲取文檔元數據的屬性。
1.1 獲取文檔信息
可使用元數據屬性來獲取一些有用的文檔信息。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Example</title>
</head>
<body>
<script>
document.writeln("<pre>"); document.writeln("document.title); document.write("</pre>"); </script> </body> </html>
理解怪異模式
compatMode 屬性告訴你瀏覽器是如何處理文檔內容的。現現在存在着大量的非標準HTML,瀏覽器則試圖顯示出這類網頁,哪怕它們並不遵循HTML規範。一些這樣的內容依賴於瀏覽器的獨特功能,而這些功能來源於瀏覽器依靠自身特色(而非遵循標準)進行競爭的年代。compatMode屬性會返回兩個值中的一個,以下表所示:
1.2 使用Location 對象
document.location 屬性返回一個Location 對象,這個對象提供了細粒度的文檔地址信息,也容許導航到其餘文檔上。下表介紹了Location對象裏的函數和屬性:
document.location 屬性最簡單的用途就是獲取當前文檔的地址信息。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>使用Location 對象</title>
</head>
<body>
<script>
document.writeln("<pre>") document.writeln("protocol: "+ document.location.protocol); document.writeln("host: "+ document.location.host); document.writeln("href: "+ document.location.href); document.writeln("hostname: "+ document.location.hostname); document.writeln("port: "+ document.location.port); document.writeln("pathname: "+ document.location.pathname); document.writeln("search: "+ document.location.search); document.writeln("hash: "+ document.location.hash); document.write("</pre>"); </script> </body> </html>
PS:當端口號爲HTTP默認的80時,屬性不會返回值
使用Location對象導航到其餘地方
還可使用Location對象(經過document.location屬性)來導航到其餘地方。具體的顯示方式有好幾種。首先,能夠爲以前示例用到的某個屬性指派新值。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Example</title>
</head>
<body>
<p id="first">
15歲的時候再獲得那個5歲的時候熱愛的布娃娃,65歲的時候終於有錢買25歲的時候熱愛的那條裙子,又有什麼意義。
什麼均可以從頭再來,只有青春不能。那麼多事情,跟青春綁在一塊兒就是美好,離開青春,就是傻冒。
</p>
<button id="pressme">Press Me</button>
<p id="second"> 你的特別不是由於你在創業,不是由於你進了牛企,不是由於你的牛offer,而是由於你就是你,堅信本身的特別,堅信本身的心裏,勇敢作本身。 IT DOESN'T MATTER WHERE YOU ARE, IT MATTERS WHO YOU ARE. </p> <img id="banana" src="imgs/banana-small.png" alt="small banna" /> <script> document.getElementById("pressme").onclick = function(){ document.location.hash = "banana"; } </script> </body> </html>
此例中包含一個button元素,當它被點擊時會給document.location.hash 屬性指派一個新值。經過一個事件把按鈕和點擊時只需的JavaScript函數關聯起來。這就是onclick屬性的做用。
這一改動會讓瀏覽器導航到某一id屬性值匹配hash值的元素上,這這個案例裏是img元素。從下面的效果圖能夠看到導航的效果:
雖然只是導航到了相同文檔的不一樣位置,但也能夠用Location對象的屬性來導航到其餘文檔。不過,這種作法一般是用href屬性實現的,由於能夠設置完整的URL。也可使用Location對象定義的一些方法。
assign和replace方法的區別在於,replace會把當前文檔從瀏覽器歷史中移除,這就意味着若是用戶點擊了後退按鈕,瀏覽器就會跳過當前文檔,就像它從未訪問過該文檔同樣。下面的例子展現瞭如何使用assign方法。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Example</title>
</head>
<body>
<button id="pressme">Press Me</button>
<script>
document.getElementById("pressme").onclick = function(){ document.location.assign("http://yexiaochao.github.io") } </script> </body> </html>
當用戶點擊button元素時,瀏覽器會導航到指定的URL上,在這個示例中是 http://yexiaochao.github.io 。
1.3 讀取和寫入cookie
cookie 屬性讓你能夠讀取、添加和更新文檔所關聯的 cookie。下面例子對此進行了演示:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Example</title>
</head>
<body>
<p id="cookiedata"></p>
<button id="write">Add Coojie</button>
<button id="update">Update Cookie</button>
<script>
var cookieCount = 0; document.getElementById("write").onclick = createCookie; document.getElementById("update").onclick = updateCookie; function readCookies(){ document.getElementById("cookiedata").innerHTML = document.cookie; } function createCookie(){ cookieCount++; document.cookie =cookieCount; readCookies(); } function updateCookie(){ document.cookie = "Cookie_"+cookieCount+"=Update_"+cookieCount; readCookies(); } </script> </body> </html>
cookie 屬性的工做方式稍微有點古怪。當讀取該屬性的值時,會獲得與文檔相關聯的全部cookie。cookie是形式爲name=value的名稱/值對。若是存在多個cookie,那麼cookie屬性會把它們做爲結果返回,之間以分號相隔,如 name1=value1;name2=value2。
與之相對,當想要建立新的cookie時,要指派新的cookie時,要指派一個新的名稱/值對做爲cookie屬性的值,它將會添加到文檔的cookie集合。一次只能設置一個cookie。若是設置的值和現有的某個cookie具有相同的名稱部分,那麼就會用值部分更新那個cookie。
爲了演示這一點,代碼中包含了一段腳原本讀取、創新和更新cookie。 readCookies 函數讀取document.cookie 屬性的值,並將結果設置爲某個段落(p)元素的內容。
這個文檔裏有兩個button元素。當Add Cookie按鈕被點擊時,createCookie函數會給cookie屬性指派一個新值,這個值會被添加到cookie集合中。Update Cookie按鈕會調用updateCookie函數。這個函數給某個現有的cookie提供一個新值。從下圖能夠看到這段腳本的效果:
從效果圖中能夠看到,添加了三個cookie,其中一個已經被更新爲某個新值。雖然添加cookie的默認形式是name=value,但能夠額外應用一些數據來改變cookie的處理方式。下表介紹了這些額外數據:
這些額外的項目能夠被附加到名稱/值對的後面,以分號分隔,就像這樣:
document.cookie = "MyCookie=MyValue;max-age=10";
1.4 理解就緒狀態
document.readyState 屬性提供了加載和解析HTML文檔過程當中當前處於哪一個階段的信息。請記住,在默認狀況下瀏覽器會在遇到文檔裏的script元素時當即執行腳本,但可使用defer屬性推遲腳本的執行。正如咱們在一些例子所見到的,可使用Javascript的事件系統來獨立執行各個函數,做爲對文檔變化或用戶操做的反饋。
在全部這些狀況下,瞭解瀏覽器加載和處理HTML到了哪一個階段可能會頗有用。readyState屬性會返回三個不一樣的值。
隨着瀏覽器逐步加載和處理文檔,readyState屬性的值從loading轉爲 interactive,再轉爲complete。這個屬性和readystatechange事件結合使用時用處最大,該事件會在每次readyState屬性的值發生變化時觸發。
下面代碼展現瞭如何同時使用這兩個事件和屬性來完成一項常見任務。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Example</title>
<script>
document.onreadystatechange = function(){ if (document.readyState == "interactive"){ document.getElementById("pressme").onclick = function(){ document.getElementById("results").innerHTML = "Button Pressed"; } } } </script> </head> <body> <button id="pressme">Press Me</button> <pre id="results"></pre> </body> </html>
這段腳本使用文檔就緒狀態來推遲一個函數的執行,直到文檔進入interactive 階段。腳本代碼要求可以找到在腳本執行時還沒有被瀏覽器載入的文檔元素。經過推遲腳本執行直至文檔加載完成,就能確認這些元素是能夠找到的。這種方式能夠做爲把script元素放到文檔末尾的替代。
1.5 獲取DOM的實現狀況
document.implementation 屬性提供了瀏覽器對DOM功能的實現信息。這個屬性返回一個DOMImplementation 對象,它包含一個 hasFeature 方法,可使用這個方法來判斷哪些DOM功能已實現。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Example</title>
</head>
<body>
<script>
var features = ["Core","HTML","CSS","Selectors-API"]; var levels = ["1.0","2.0","3.0"]; document.writeln("<pre>") for(var i = 0; i < features.length; i++){ document.writeln("Checking for features: "+features[i]); for (var j=0; j<levels.length; j++){ document.write(features[i]+" Level "+levels[j]+": "); document.writeln(document.implementation.hasFeature(features[i],levels[j])) } } document.write("</pre>"); </script> </body> </html>
這段腳本檢測了若干不一樣的DOM功能,以及所定義的功能等級。它並不像看上去那麼有用。首先,瀏覽器並不老是能正確報告它們實現的功能。某些功能實現並不會經過hasFeature方法進行報告,而另外一些報告了卻根本沒有實現。其次,瀏覽器報告了某項功能並不意味着它的實現方式是有用的。雖然這個問題不如之前嚴重,但DOM的實現是存在一些差異的,
若是你打算編寫能在全部主流瀏覽器上工做的代碼(你也應該這樣想),那麼hasFeature方法的用處不大。你應該選擇在測試階段全面檢查代碼,在須要的時候測試支持狀況和備用措施,同時也能夠考慮使用某個JavaScript庫(例如jQuery),它能夠消除不一樣DOM實現之間的差異。
2. 獲取 HTML 元素文檔
Document 對象的一大關鍵功能是做爲一個入口,能訪問表明文檔裏各個元素的對象。能夠用幾種不一樣的方法來執行這個任務。有些屬性會返回表明特定文檔元素類型的對象,有些方法能很方便地運用條件搜索來找到匹配的元素,還能夠將DOM視爲一棵樹並沿着它的結構進行導航。
2.1 使用屬性獲取元素對象
Document對象提供了一組屬性,它們會返回表明文檔中特定元素或元素類型的對象。
上表裏描述的大多數都返回一個HTMLCollection 對象。DOM就是用這種方式來表示一組表明元素的對象集合。下面代碼演示了訪問集合內對象的兩種方法。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Example</title>
<style>
pre { border: medium double black;} </style> </head> <body> <pre id="results"></pre> <img id="lemon" src="imgs/lemon.png" alt="Lemon" /> <img src="imgs/apple.png" id="apple" alt="apple" /> <img src="imgs/banana-small.png" alt="small banana" id="banana"> <script> var resultsElement = document.getElementById("results"); var elems = document.images; for(var i=0;i<elems.length;i++){ resultsElement.innerHTML += "Imgage Element: "+elems[i].id +"\n"; } var srcValue = elems.namedItem("apple").src; resultsElement.innerHTML += "Src for apple element is: "+ srcValue + "\n"; </script> </body> </html>
第一種使用HTMLCollection 對象的方法是將它視爲一個數組。它的length 屬性會返回集合裏的項目數量,它還支持使用標準的 JavaScript 數組索引標記(element[i]這種表示方法)來直接訪問集合裏的各個對象。此例中用 document.images 屬性得到了一個 HTMLCollection, 它包含了全部表明文檔裏 img 元素的對象。
第二種方法是使用 namedItem 方法,它會返回集合裏帶有指定id或name屬性值的項目。此例中使用了namedItem方法來獲取表明某個特定img元素的對象,該元素的id屬性值爲apple。
此例效果圖以下:
2.2 搜索元素
Document 對象定義了許多方法,能夠用它們搜索文檔裏的元素。
這些方法中的一些方法會返回多個元素。在表裏它們展示爲返回一個HTMLElement對象數組,但嚴格來講並不是如此。事實上,這些方法返回一個NodeList,它是底層DOM規範的一部分,處理的是通用結構文檔格式,而不只僅是HTML。可是,對這些用途而言,能夠將它們視爲數組,把注意力集中在HTML5上。
這些搜索方法能夠被分紅兩類。下面代碼演示了其中一類,即名稱 getElement開頭的那些方法。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Example</title>
<style>
pre { border: medium double black;} </style> </head> <body> <pre id="results"></pre> <img id="lemon" class="fruits" name="apple" src="imgs/lemon.png" alt="Lemon" /> <p> There are lots of different kinds of fruits - there are over 500 varieties of bananas alone. By the time we add the countless types of apples, oranges, and other well-known fruit, we are faced with thousands of choices. </p> <img id="apple" class="fruits" name="apple" src="imgs/apple.png" alt="apple" /> <p> One of the most interesting aspects of fruit is the variety available in each country. I live near London, in an area which is know for its apples. </p> <img id="banana" src="imgs/banana-small.png" alt="small banana"> <script> var resultElement = document.getElementById("results"); var pElems = document.getElementsByTagName("p"); resultElement.innerHTML += "There are " + pElems.length + " p elements\n"; var fruitsElems = document.getElementsByClassName("fruits"); resultElement.innerHTML += "There are "+ fruitsElems.length + " elements in the fruits class\n"; var nameElems = document.getElementsByName("apple"); resultElement.innerHTML += "There are " + nameElems.length + " elements with the name 'apple'"; </script> </body> </html>
在使用 getElementById方法時,若是找不到帶有指定id值的元素,瀏覽器就會返回null。與之相對,其餘的方法老是會返回一個HTMLElement對象數組,但若是找不到匹配,length屬性就會返回0。
用CSS選擇器進行搜索
使用CSS選擇器是一種有用的替代性搜索方式。選擇器能夠在文檔裏找到範圍更廣的元素。
修改前面示例的JavaScript代碼以下:
<script>
var resultsElement = document.getElementById("results"); var elems = document.querySelectorAll("p,img#apple"); resultsElement.innerHTML += "The selector matched "+ elems.length + " elements\n" </script>
此例中使用了一個選擇器,它會匹配全部的p元素和id值爲apple的img元素。用其餘document方法很難達到一樣的效果。
2.4 合併進行鏈式搜索
DOM的一個實用功能是幾乎全部Document對象實現的搜索方法同時也能被HTMLElement對象實現(一個例外),這使得能夠合併進行鏈式搜索。惟一的例外是getElementById方法,只有Document對象才能使用它。下面代碼展現了鏈式搜索:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>合併進行鏈式搜索</title>
<style>
pre { border: medium double green;} </style> </head> <body> <pre id="results"></pre> <p id="tblock"> There are lots of different kinds of fruit - there are over 500 varieties of <span id="banana">banana</span> alone. Bt the time we add the countless types of <span id="apple">apples</span>, <span id="orange">oranges</span>, and other well-known fruit, we are faced with thousands of choices. </p> <script> var resultsElement = document.getElementById("results"); var elems = document.getElementById("tblock").getElementsByTagName("span"); resultsElement.innerHTML += "There are " + elems.length + " span elements\n"; var elems2 = document.getElementById("tblock").querySelectorAll("span"); resultsElement.innerHTML += "There are " + elems2.length + " span elements (Mix)\n"; var selElems = document.querySelectorAll("#tblock > span"); resultsElement.innerHTML += "There are " + selElems.length + " span elements (CSS)\n"; </script> </body> </html>
此例中有兩次鏈式搜索,這兩次都從getElementById方法開始(它會返回以後進行處理的單個對象)。第一次連接中,使用getElementsByTagName方法連接了一個搜索;在第一次連接中,則經過querySelectorAll方法使用了一個很是簡單的CSS選擇器。這些連接都返回了一個span元素的集合,它們都位於id爲tblock的p元素以內。
固然,也能夠經過單獨給Document對象應用CCS選擇器方法來實現一樣的效果,可是這一功能在某些狀況下會很方便,好比處理由腳本中的其餘函數(或第三方腳本)所生成的HTMLElement對象。此例顯示效果以下:
3. 在DOM樹裏導航
另外一種搜索方法是將DOM視爲一棵樹,而後在它的層級結構裏導航。全部的DOM對象都支持一組屬性和方法來作到這點。
下面代碼展現了一段腳本,它能夠導航到文檔各處,並在一個pre元素裏顯示當前所選元素的信息。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>在DOM樹裏導航</title>
<style>
pre { border: medium double green;} </style> </head> <body> <pre id="results"></pre> <p id="tblock"> There are lots of different kinds of fruit - there are over 500 varieties of <span id="banana">banana</span> alone. Bt the time we add the countless types of <span id="apple">apples</span>, <span id="orange">oranges</span>, and other well-known fruit, we are faced with thousands of choices. </p> <img id="apple" class="fruits images" name="apple" src="../imgs/apple.png" alt="apple" /> <img id="banana" src="../imgs/banana-small.png" alt="small banana" /> <p> One of most interesting aspects of fruit is the variety available in each country. I live near London, in an area which is known for its apple. </p> <p> <button id="parent">Parent</button> <button id="child">First Child</button> <button id="prev">Prev Sibling</button> <button id="next">Next Sibling</button> </p> <script> var resultsElem = document.getElementById("results"); var element = document.getElementById("tblock"); var buttons = document.getElementsByTagName("button"); for(var i = 0; i < buttons.length; i++){ buttons[i].onclick = handleButtonClick; } processNewElement(element); function handleButtonClick(e){ if(element.style){ element.style.backgroundColor = "white"; } if(e.target.id == "parent" && element != document.body){ element = element.parentNode; }else if(e.target.id == "child" && element.hasChildNodes()){ element = element.firstChild; }else if(e.target.id == "prev" && element.previousSibling){ element = element.previousSibling; }else if(e.target.id == "next" && element.nextSibling){ element = element.nextSibling; } processNewElement(element); if(element.style){ element.style.backgroundColor = "lightgrey"; } } function processNewElement(elem){ resultsElem.innerHTML = "Element type: " + elem + "\n"; resultsElem.innerHTML += "Element id: " + elem.id + "\n"; resultsElem.innerHTML += "Has child nodes: " + elem.hasChildNodes() + "\n"; if(elem.previousSibling){ resultsElem.innerHTML += ("Prev sibling is: " + elem.previousSibling + "\n"); }else { resultsElem.innerHTML += "No prev sibling\n"; } if (elem.nextSibling){ resultsElem.innerHTML += "Next sibling is " + elem.nextSibling + "\n"; }else { resultsElem.innerHTML += "No next sibling\n"; } } </script> </body> </html>
這段腳本的重要之處用粗體進行顯示,它們是實際進行導航操做的部分。腳本的其他部分則是在作準備工做,處理按鈕點擊以及顯示當前所選元素的信息。