理解DOM
在這一部分,你將開始探索文檔對象模型(DOM)。通過使用DOM,你能夠添加、移除和操作各種元素。還可以使用事件(event)來響應用戶的交互操作,以及完全控制CSS。
從這里開始,你就處於HTML5的程序設計部分了。在此之前,你已經用元素和CSS聲明創建了內容,現在是時候以程序員的身份開始使用JavaScript了。
理解文檔對象模型
DOM是一組對象的集合,這些對象代表了HTML文檔里的各個元素。顧名思義,DOM就像一個模型,它由代表文檔的眾多對象組成。DOM是Web開發的關鍵工具之一,它是HTML文檔的結構和內容與JavaScript之間的橋梁。作為示例,代碼清單1展示了一個簡單的HTML文檔。
代碼清單1 一個簡單的HTML文檔
<!DOCTYPE>
<html>
<head>
<title>一個簡單的HTML文檔</title>
<meta name="作者" content="黃子涵"/>
<meta name="描述" content="一個簡單的例子"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<p id="FloatingLife">
<span id="monologue">獨白:</span><br>
<br>
當你意識到自己其實已經不再那么年輕<br>
每天周而復始的過着自己可能並不喜歡卻無法改變的生活<br>
做着自己並不喜歡的工作<br>
人生的選擇題<br>
是要繼續甘於平庸<br>
還是奮力一搏去追求自己所想要的<br>
成功或者失敗<br>
得到或者失去<br>
也往往不那么重要<br>
因為我們只想要當下<br>
</p>
<P id="DifficultSutra">
吞風吻雨葬落日未曾彷徨<br>
欺山趕海踐雪徑也未絕望<br>
拈花把酒偏折煞世人情狂<br>
憑這兩眼與百臂或千手不能防<br>
天闊闊雪漫漫共誰同航<br>
這沙滾滾水皺皺笑着浪盪<br>
貪歡一晌偏教那女兒情長埋葬<br>
</P>
</body>
</html>
從上圖可以看到瀏覽器是如何顯示上述示例HTML文檔的。
作為顯示HTML文檔過程中的一個步驟,瀏覽器會解析HTML並創建一個模型。這個模型保存了各個HTML元素之間的層級關系(如下圖所示),每個元素都由一個JavaScript對象表示。
你可以用DOM來獲取文檔信息,也可以對其進行修改。這是現代Web應用程序的基礎。
模型里的每一個對象都有若干屬性和方法。當你用它們來修改對象的狀態時,瀏覽器會讓這些改動反映到對應的HTML元素上,並更新你的文檔。
所有代表元素的DOM象都支持同一組基本功能:HTMLElement對象和其定義的核心功能始終是可用的,無論對象代表何種元素都是如此。另外,某些對象會定義一些額外的功能,這些操作反映了特定HTML元素獨一無二的特性。記住下面的一點很重要:文檔模型里任何代表某個元素的對象都至少能支持HTMLElement功能,其中一些還支持額外的功能。
不是所有可供使用的對象都代表了HTML元素。正如你即將看到的,一些對象代表元素的集合,另一些則代表DOM自身的信息,當然還有Document這個對象,它是我們探索DOM的入口。
注意
如果你熟悉面向對象程序設計的概念,那么了解HTMLElement是一個接口可能會有所幫助,它是由DOM所包含的對象實現的。用於代表具體元素的對象是HTMLElement派生出來的接口,意思是你既可以把某個對象當做HTMLElement的實現,也可以當做其更為具體的子類型。如果你不熟悉面向對象的概念也不用擔心。對主流Web程序設計而言,是否理解它們無關緊要。簡單起見,下面將把所有的一切都稱為對象。
理解DOM Level和兼容性
開始使用DOM時,你會碰到網絡上一些文章和教程提到DOM Level(DOM等級,比如某個特定功能是在DOM Level3中定義的)。DOM Level是標准化過程中的版本號,在大多數情況下應該忽略它們。
DOM的標准化過程並不是完全成功的,每一個DOM Level都有描述它的標准和文檔,但它們並沒有被完整地實現,瀏覽器只是簡單地挑選了其中的有用功能,而忽略了其他的。更糟糕的是,已經實現的功能之間還存在着某種程度的不一致性。
部分問題在於,DOM規范與HTML標准過去是分別開發的。HTML5試圖通過包含一組必須實現的DOM核心功能來解決這個問題。然而這種做法尚未見效,碎片化仍然存在。
有多種方式可用來應對DOM功能的多變性。第一種方式是使用某個JavaScript庫(比如jQuery),它消除了瀏覽器之間實現方式的差別。使用庫的優點在於其一致性,但缺點是只能使用庫支持的那些功能。如果想突破庫原有功能的局限,就只能轉回到直接操作DOM上,並重新面對之前的那些問題。(這並不是說jQuery和類似的庫沒有價值,它們很有用,非常值得去了解一下。)
第二種是保守方式:只使用你所知的被廣泛支持的那些功能。這種方式一般來說是最為明智的,不過它需要仔細而全面的測試。不僅如此,你還必須仔細測試新版的瀏覽器,確保對這些功能的支持沒有發生變化或者被移除。
測試DOM功能
第三種方式是測試與某一功能相關的DOM對象屬性或方法是否存在。代碼清單2包含了一個簡單的例子。
代碼清單2 測試某個功能
<!DOCTYPE>
<html>
<head>
<title>測試某個功能</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<p id="MoveBack">
天空灰得像哭過<br>
酸酸的空氣<br>
嗅出我們的距離<br>
一幕錐心的結局<br>
像呼吸般無法停息<br>
抽屜泛黃的日記<br>
榨干了回憶<br>
<img src="http://120.77.46.246/src/img/Xu_Weizhou.jpeg">
</p>
<script>
var images;
if (document.querySelectorAll) {
images = document.querySelectorAll("#MoveBack > img");
} else {
images = document.getElementById("MoveBack").getElementsByTagName("img");
}
for (var i = 0; i < images.length; i++) {
images[i].style.border = "thick soild balck";
images[i].style.padding = "4px";
}
</script>
</body>
</html>
在這個例子里,腳本使用一條if語句來判斷document對象是否定義了一個名為querySelectorAll的方法。如果這條語句的計算結果是true,那么瀏覽器是支持這一功能的,我就可以開始使用它。如果該語句的計算結果是false,那么我可以換一種方式來達到同樣的目的。
談到DOM時,你經常看到的就是剛才這種建議,但它過於草率,沒有指出其中的缺陷,而這些缺陷有可能很嚴重。
第一個缺陷在於,並不總是存在另一種方式能實現某個給定功能的效果。代碼清單2能順利工作是因為我測試的功能是其他函數的一種便利性加強形式,但情況並不總是如此。
第二個缺陷是我只測試了該功能是否存在,而不是它的實現質量和一致性。許多功能(特別是新的功能)需要多個版本的瀏覽器才能穩定下來並實現一致性。雖然這個問題不像以前那樣嚴重,但你也許很容易就會遇到意料之外的結果,因為你依賴的瀏覽器功能實現方式存在差別。
第三個缺陷是必須測試每一種你所依賴的功能。這么做需要耗費大量的精力,而且產生的代碼充斥着無窮無盡的測試。我並不是說它不是一種有用的技巧,而是它存在缺陷,不應該取代恰當的測試。
DOM快速查詢
以下部分提供了對象、方法、屬性和事件的快速查詢。
Document的成員
Document對象,它代表當前的文檔,也是你探索DOM的入口。下表概述了此對象所定義的成員。
Document對象
名 稱 | 說 明 | 返 回 |
---|---|---|
activeElement | 返回代表文檔中當前獲得焦點元素的對象 | HTMLElement |
body | 返回代表文檔中body元素的對象 | HTMLElement |
characterSet | 返回文檔的字符集編碼。這是一個只讀屬性 | 字符串 |
charset | 獲取或設置文檔的字符集編碼 | 字符串 |
childNodes | 返回子元素的集合 | HTMLElement[] |
compatMode | 獲取文檔的兼容性模式 | 字符串 |
cookie | 獲取或設置當前文檔的cookie | 字符串 |
defaultCharset | 獲取瀏覽器所使用的默認字符編碼 | 字符串 |
defaultview | 返回當前文檔的Window對象 | Window |
dir | 獲取或設置文檔的文本方向 | 字符串 |
domain | 獲取或設置當前文檔的域名 | 字符串 |
embeds、plugins | 返回所有代表文檔中embed元素的對象 | HTMLCollection |
firstChild | 返回某個元素的第一個子元素 | HTMLElement |
forms | 返回所有代表文檔中form元素的對象 | HTMLCollection |
getElementById(<id >) |
返回帶有指定id值的元素 | HTMLElement |
getElementsByClassName(<class >) |
返回帶有指定class值的元素 | HTMLElement[] |
getElementsByName(<name >) |
返回帶有指定name值的元素 | HTMLElement[] |
getElementsByTagName(<tag >) |
返回帶有指定類型的元素 | HTMLElement[] |
hasChildNodes() | 如果當前元素有子元素則返回true | 布爾值 |
head | 返回代表head元素的對象 | HTMLHeadElement |
images | 返回所有代表img元素的對象 | HTMLCollection |
implementation | 提供關於DOM可用功能的信息 | DOMImplementation |
lastchild | 返回最后一個子元素 | HTMLElement |
lastModified | 返回文檔的最后修改時間 | 字符串 |
links | 返回所有代表文檔中具備href的a和area元素的對象 | HTMLCollection |
location | 提供關於當前文檔URL的信息 | Location |
nextSibling | 返回位於當前元素之后的兄弟元素 | HTMLElement |
parentNode | 返回父元素 | HTMLElement |
previousSibling | 返回位於當前元素之前的兄弟元素 | HTMLElement |
querySelector(<selector >) |
返回匹配特定CSS選擇器的第一個元素 | HTMLElement |
querySelectorAll(<selector >) |
返回匹配特定CSS選擇器的所有元素 | HTMLElement[] |
readyState | 返回當前文檔的狀態 | 字符串 |
referrer | 返回鏈接到當前文檔的文檔URL (它是對應HTTP標頭的值) | 字符串 |
scripts | 返回所有代表script元素的對象 | HTMLCollection |
title | 獲取或設置當前文檔的標題 | 字符串 |
下表概述了Location對象。
Location 對象
名 稱 | 說 明 | 返 回 |
---|---|---|
assign(<URL >) |
導航到指定的URL上 | void |
hash | 獲取或設置文檔URL的錨(井號串)部分 | 字符串 |
host | 獲取或設置文檔URL的主機名和端口號部分 | 字符串 |
hostname | 獲取或設置文檔URL的主機名部分 | 字符串 |
href | 獲取或設置當前文檔的地址 | 字符串 |
pathname | 獲取或設置文檔URL的路徑部分 | 字符串 |
port | 獲取或設置文檔URL的端口號部分 | 字符串 |
protocol | 獲取或設置文檔URL的協議部分 | 字符串 |
reload() | 重新加載當前文檔 | void |
replace(<URL >) |
清除當前文檔並導航至URL所指定的新文檔 | void |
resolveURL(<URL >) |
將指定的相對URL解析為絕對URL | 字符串 |
search | 獲取或設置文檔URL的查詢(問號串)部分 | 字符串 |
Window 的成員
Window對象
名 稱 | 說 明 | 返 回 |
---|---|---|
alert(<msg >) |
向用戶顯示一個對話框窗口並等候其被關閉 | void |
blur() | 讓窗口失去鍵盤焦點 | void |
clearlnterval(<id >) |
撤銷某個時間間隔計時器 | void |
clearTimeout(<id >) |
撤銷某個超時計時器 | void |
close() | 關閉窗口 | void |
confirm(<msg >) |
顯示一個帶有確認和取消提示的對話框窗口 | 布爾值 |
defaultView | 返回活動文檔的Window | Window |
document | 返回與此窗口關聯的Document對象 | Document |
focus() | 讓窗口獲得鍵盤焦點 | void |
frames | 返回文檔內嵌iframe元素的Window對象數組 | Window[] |
history | 提供對瀏覽器歷史的訪問 | History |
innerHeight | 獲取窗口內容區域的高度 | 數值 |
innerWidth | 獲取窗口內容區域的寬度 | 數值 |
length | 返回文檔內嵌的iframe元素數量 | 數值 |
location | 提供當前文檔地址的詳細信息 | Location |
opener | 返回打開當前瀏覽器上下文環境Window | Window |
outerHeight | 獲取窗口的高度,包括邊框和菜單欄等 | 數值 |
outerWidth | 獲取窗口的寬度,包括邊框和菜單欄等 | 數值 |
pageXOffet | 獲取窗口從左上角算起水平滾動過的像素數 | 數值 |
pageYOffset | 獲取窗口從左上角算起垂直滾動過的像素數 | 數值 |
parent | 返回當前Window的父Window | Window |
postMessage(<msg >,<origin >) |
給另一個文檔發送消息 | void |
print() | 提示用戶打印頁面 | void |
prompt(<msg >, <val >) |
顯示對話框提示用戶輸入一個值 | 字符串 |
screen | 返回一個描述屏幕的Screed象 | Screen |
screenLeft、ScreenX | 獲取從窗口左邊緣到屏幕左邊緣的像素數 | 數值 |
screenTop、screenY | 獲取從窗口上邊緣到屏幕上邊緣的像素數 | 數值 |
scrollBy(<x >, <y >) |
讓文檔相對其當前位置進行滾動 | void |
scrollTo(<x >, <y >) |
滾動到指定的位置 | void |
self | 返回當前文檔的Window | Window |
setInterval(<function >, <time >) |
創建一個計時器,每隔time毫秒調用指定的函數 | 整數 |
setTimeout(<function >, <time >) |
創建一個計時器,等待time毫秒后調用指定的函數 | 整數 |
showModalDialog(<url >) |
彈出一個窗口,顯示指定的URL | void |
stop() | 停止載入文檔 | void |
top | 返回最上層的Window | Window |
下表概述了History對象的成員。
History對象
名稱 | 說 明 | 返 回 |
---|---|---|
back() | 在瀏覽歷史里后退一步 | void |
forward() | 在瀏覽歷史里前進一步 | void |
go(<index >) |
轉到相對於當前文檔的某個瀏覽歷史位置。正值是前進,負值是后退 | void |
length | 返回瀏覽歷史里的項目數量 | 數值 |
pushState(<state >, <title >, <url >) |
向瀏覽器歷史添加一個條目 | void |
replaceState(<state >, <title >, <url >) |
替換瀏覽器歷史中的當前條目 | void |
state | 返回瀏覽器歷史里關聯當前文檔的狀態數據 | 對象 |
下表概述了Screen對象的成員。
Screen對象
名 稱 | 說 明 | 返 回 |
---|---|---|
availHeight | 返回屏幕上可供顯示窗口部分的高度(排除工具欄之類) | 數值 |
availWidth | 返回屏幕上可供顯示窗口部分的寬度(排除工具欄之類) | 數值 |
colorDepth | 返回屏幕的顏色深度 | 數值 |
height | 返回屏幕的高度 | 數值 |
width | 返回屏幕的寬度 | 數值 |
HTMLElement的成員
HTMLElement對象,它代表了文檔里的各種HTML元素。下表概述了此對象定義的成員。
HTMLElement對象
名 稱 | 說 明 | 返 回 |
---|---|---|
checked | 獲取或設置checked屬性的存在狀態 | 布爾值 |
classList | 獲取或設置元素所屬類的列表 | DOMTokenList |
className | 獲取或設置元素所屬類的列表 | 字符串 |
dir | 獲取或設置dir屬性的值 | 字符串 |
disabled | 獲取或設置disabled屬性的存在狀態 | 布爾值 |
hidden | 獲取或設置hidden屬性的存在狀態 | 布爾值 |
id | 獲取或設置id屬性的值 | 字符串 |
lang | 獲取或設置lang屬性的值 | 字符串 |
spellcheck | 獲取或設置spellcheck屬性的存在狀態 | 布爾值 |
tabIndex | 獲取或設置tabindex屬性的值 | 數值 |
tagName | 返回標簽名(象征元素的類型) | 字符串 |
title | 獲取或設置title屬性的值 | 字符串 |
add(<class >) |
給元素添加指定的類 | void |
contains(<class >) |
如果元素屬於指定的類則返回true | 布爾值 |
length | 返回元素所屬類的數量 | 數值 |
remove(<class >) |
從元素上移除指定的類 | void |
toggle(<class >) |
如果類不存在就添加它,如果存在則移除它 | 布爾值 |
attributes | 返回應用到元素上的屬性 | Attr[] |
dataset | 返回以data-開頭的屬性 | 字符串數組[<name >] |
getAttribute(<name >) |
返回指定屬性的值 | 字符串 |
hasAttribute(<name >) |
如果元素帶有指定屬性則返回true | 布爾值 |
removeAttribute(<name >) |
從元素上移除指定屬性 | void |
setAttribute(<name >, <value >) |
應用一個指定名稱和值的屬性 | void |
appendChild(HTMLElement) | 將指定元素附加為當前元素的子元素 | HTMLElement |
cloneNode(boolean) | 復制某個元素 | HTMLElement |
compareDocumentPosition(HTMLElement) | 判斷某個元素的相對位置 | 數值 |
innerHTML | 獲取或設置元素的內容 | 字符串 |
insertAdjacentHTML(〈pos 〉,<text >) |
相對於元素的位置插入HTML | void |
insertBefore(<newelem >, <childElem >) |
將第一個元素插入到第二個(子)元素之前 | HTMLElement |
isEqualNode(<HTMLElement >) |
判斷指定元素是否與當前元素等同 | 布爾值 |
isSameNode(HTMLElement) | 判斷指定元素是否就是當前元素 | 布爾值 |
outerHTML | 獲取或設置某個元素的HTML和內容 | 字符串 |
removeChild(HTMLElement) | 從當前元素上移除指定的子元素 | HTMLElement |
replaceChild(HTMLElement, HTMLElement) | 替換當前元素的某個子元素 | HTMLElement |
createElement(<tag >) |
用指定標簽類型創建一個新的HTMLElement對象 | HTMLElement |
createTextNode(<text >) |
用指定內容創建一個新的Text對象 | Text |
Text對象,它用於代表文檔中的文本內容。下表描述了Text對象的成員。
Text對象
名 稱 | 說 明 | 返 回 |
---|---|---|
appendData(<string >) |
在文本塊的末尾附加指定字符串 | void |
data | 獲取或設置文本 | 字符串 |
deleteData(<offset >, <count >) |
移除字符串中的文本。第一個數字是偏移量,第二個數字是要移除的字符數量 | void |
insertData(<offset >, <string >) |
在指定的偏移量位置插入指定字符串 | void |
length | 返回字符數量 | 數值 |
replaceData(<offset >, <count >, <string >) |
用指定字符串替換一部分文本 | void |
replaceWholeText(<string >) |
替換全部文本 | Text |
splitText(<number >) |
將現有的Text元素在指定的偏移量處一分為二。 | Text |
substringData(<offset >, <count >) |
返回文本的子串 | 字符串 |
wholeText | 獲取文本 | 字符串 |
DOM里的CSS屬性
下表列出了CSSStyleDeclaration對象的屬性和它們所對應的樣式。
CSSStyleDeclaration對象的成員
成 員 | 對應於 |
---|---|
background | background |
backgroundAttachment | background-attachment |
backgroundColor | background-color |
backgroundimage | background-image |
backgroundposition | background-position |
backgroundRepeat | background-repeat |
border | border |
borderBottom | border-bottom |
borderBottomColor | border-bottom-color |
borderBottomStyle | border-bottom-style |
borderBottomWidth | border-bottom-width |
borderCollapse | border-collapse |
borderColor | border-color |
borderLeft | border-left |
borderLeftColor | border-left-color |
borderLeftStyle | border-left-style |
borderLeftWidth | border-left-width |
borderRight | border-right |
borderRightColor | border-right-color |
borderRightStyle | border-right-style |
borderRightWidth | border-iight-width |
borderSpacing | border-spacing |
borderStyle | border-style |
borderTop | border-top |
borderTopColor | border-top-color |
borderTopStyle | boider-top-style |
borderTopWidth | border-top-width |
borderWidth | border-width |
captionSide | caption-side |
clear | clear |
color | color |
cssFloat | float |
cursor | cursor |
direction | direction |
display | display |
emptyCells | empty-cells |
font | font |
fontFamily | font-family |
fontSize | font-size |
FontStyle | font-style |
fontVariant | font-variant |
fontweight | font-weight |
height | height |
letterSpacing | letter-spacing |
lineHeight | line-height |
liststyle | list-style |
listStylelmage | list-style-image |
listStylePosition | list-style-position |
listStyleType | list-style-type |
margin | margin |
marginBottom | margin-bottom |
marginLeft | margin-left |
marginRight | margin-right |
marginTop | margin-top |
maxHeight | max-height |
maxWidth | max-width |
minHeight | min-height |
minWidth | min-width |
outline | outline |
outlineColor | outline-color |
outlineStyle | outline-style |
outlineWidth | outline-width |
overflow | overflow |
padding | padding |
paddingBottom | padding-bottom |
paddingLeft | padding-left |
paddingRight | padding-right |
paddingTop | padding-top |
tableLayout | table-layout |
textAlign | text-align |
textDecoration | text-decoration |
textindent | text-indent |
textshadow | text-shadow |
textTransform | text-transform |
visibility | visibility |
whitespace | whitespace |
width | width |
wordSpacing | word-spacing |
zIndex | z-index |
DOM中的事件
DOM的事件系統,有許多不同的事件可供使用,如下表所示。
DOM的事件
名 稱 | 說 明 |
---|---|
blur | 在元素失去鍵盤焦點時觸發 |
click | 在按下鼠標按鈕后釋放時觸發 |
dblclick | 在兩次按下鼠標按鈕並釋放時觸發 |
focus | 在元素獲得鍵盤焦點時觸發 |
focusin | 在元素即將獲得鍵盤焦點時觸發 |
focusout | 在元素即將失去鍵盤焦點時觸發 |
keydown | 在用戶按下某個鍵時觸發 |
keypress | 在用戶按下某個鍵並釋放時觸發 |
keyup | 在用戶釋放某個鍵時觸發 |
mousedown | 在鼠標按鈕被按下時觸發 |
mouseenter | 在光標移入元素或其下屬元素所占據的屏幕區域時觸發 |
mouseleave | 在光標移出元素及其所有下屬元素所占據的屏幕區域時觸發 |
mousemove | 在光標位於元素上方並移動時觸發 |
mouseout | 與mouseleave相似,區別是當光標還在下屬元素上方時此事件也會被觸發 |
mouseover | 與mouseenter相似,區別是當光標還在下屬元素上方時此事件也會被觸發 |
mouseup | 在鼠標按鈕被釋放時觸發 |
onabort | 在文檔或資源的加載過程被中止時觸發 |
onafterprint | 在用戶打印文檔后觸發 |
onbeforeprint | 在調用Window.print()方法之后,向用戶呈現打印選項之前觸發 |
onerror | 在文檔或資源載入岀錯時觸發 |
onhashchange | 在地址的錨(井號串)部分變動時觸發 |
onload | 在文檔或資源載入完成時觸發 |
onpopstate | 觸發時會提供一個關聯瀏覽器歷史的狀態對象 |
onresize | 在窗口大小改變時觸發 |
onunload | 在文檔從窗口或瀏覽器中卸載時觸發 |
readystatechange | 在ready State屬性的值改變時觸發 |
reset | 在某張表單被重置時觸發 |
submit | 在某張表單被提交時觸發 |