理解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 | 在某张表单被提交时触发 |
