文档对象模型:对HTML的映射
基础知识回顾:
DOM 即(Document Object Model),文档对象模型,DOM实际是把HTML当作XML文件来进行处理,用对象的眼光来打量HTML,可以说DOM是继HTML后Web的最有用的发明。
文档对象模型(DOM)是表示文档(比如HTML和XML)和访问、操作构成文档的各种元素的应用程序接口(API)。一般的,支持 Javascript的所有浏览器都支持DOM。本文所涉及的DOM,是指W3C定义的标准的文档对象模型,它以树形结构表示HTML和XML文档,定义 了遍历这个树和检查、修改树的节点的方法和属性。
在DOM中,HTML文档的每个元素都是一个对象,属性和文本也都是对象。JavaScript能够独立访问每个对象,通过使用内建函数也能轻松地发现或改变所需的对象。
DOM眼中的HTML文档:树
在DOM眼中,HTML跟XML一样是一种树形结构的文档,对于W3C DOM而言,HMTL文档中的任何一样东西都是一个节点。整篇文档是一个文档节点(document node);在每一个HTML中的标签都是一个元素节点。比如:<html>是根(root)节点,<head>、< title>、<body>是<html>的子(children)节点,互相之间是兄弟(sibling)节点。
按照HMTL语言这种嵌套的层次结构,所有的元素就映射成了一个棵DOM树。这棵树从文档节点自身开始扩展分支,直到所有位于末端的文本节点。
以这个简单的HTML页面为例:
1 | |
元素节点是DOM节点的一种类型,DOM结构中的大部分节点都是元素节点 ;但在实际的文档中,还包括另外两种节点:文本节点 和属性节点
节点类型
元素节点
即表示HTML元素的节点。有那些请看 第四章.HTML 4.01/XHTML 1.0 元素列表
文本节点
在HMTL代码中,在成对的尖括号(<>)外的所有内容都会被视为DOM的文本节点。从结构上说,文本节点和元素节点是基本相同的,它们和元素节点同处于树型结构中,也像元素节点那样被访问;但文本节点是没有子节点的。
注意:
文本节点不仅可以包含可见字符,还可以包含一些不可见的字符,例如换行符,tab等符号。
正如我们在例子中看到的代码一样,要使代码更容易与阅读,就需要换行符或TAB符号来分离标签或文本,这样都将被视为一个文本节点对待的
这就意味着相邻的元素之间要用文本节点分隔的,或者在文本节点的开始或结尾处用空白来分离的。不同的浏览器对空白节点的处理方法是不同的,鉴于DOM解析中的这种可变性,处理DOM节点的数目及顺序应格外谨慎。
举例说明:
换行符,tab等符号格式化的代码
1 | |
为了看出这种区别,我们可以遍历test的子节点,并将其节点个数及节点类型都打印出来:
1 | |
结果:
IE中:
1 | |
非IE中:
1 | |
两种不同的结果这就是我上面说的原因导致的。
在这种情况下,唯一有可能的原因就是在HTML的书写上,因为这段HTML并不是连续的书写,而是每个节点间都用回车换行了,非IE把换行也当成了一个节点。
连续的书写的HTML
1 | |
在IE和非IE中得到了一样的结果
1 | |
我还要说的就是“鉴于DOM解析中的这种可变性,处理DOM节点的数目及顺序应格外谨慎。”
属性节点
元素节点和文本节点分别用来表示标签和文本,除此之外,DOM中还需要说明的信息就是属性了。
简单的地说,属性应该是元素的一部分,从某种角度上看也是的确如此。但是属性也是一种节点类型,称作属性节点 。
正如图片上的示例DOM结构,任何一个anchor元素都可以加上href和title属性节点。
属性节点通常是依附于元素节点的,但和元素节点及文本节点有着本质的不同,DOM结构对于它们并不适用,属性节点并没有被看做它们所依附节点的子节点。
因此,操作属性节点通过特殊的函数实现,稍后我们将讨论这类函数。
获取节点(寻找元素)
正如前面所看到的DOM结构一样,即使是对于一个简单的文档,其DOM结构也会很快变得相当复杂。
因此需要一种有效的方法来识别和操作DOM中的节点。
在很多方面,利用DOM来操作元素都和应用CSS中的元素样式相似,都采用了如下的所示的常规模式:
- 指定需要影响的元素或元素组;
- 说明希望对应该元素或元素实现的效果。
同时,它们查找元素的过程也十分相似。
长途旅行
我看到的下面,说的这两个方法,如果你能给它们正确的指令并正确书写函数(javascript是区分大小写的),它们能找到整个文档中的任何一个HTML元素。
-
getElementById()
- 该方法将返回一个与那个有着给定id属性值的元素节点相对应的对象。
- 如果您需要查找文档中的一个特定的元素,最有效的方法是 getElementById()。 getElementsByTagName()
- 该方法返回一个对象数组,每个对象分别对应着文档里有着给定标签的一个元素。
- 即,该方法可返回带有指定标签名的对象的集合。
- getElementsByTagName() 方法返回元素的顺序是它们在文档中的顺序。
- 如果把特殊字符串 “*” 传递给 getElementsByTagName() 方法,它将返回文档中所有元素的列表,元素排列的顺序就是它们在文档中的顺序。
1. getElementById() # 通过ID属性查找元素
实战:
1 | |
1 | |
注意:
我在网页设计时尽量保持元素ID的唯一性。
如果指定的ID值的元素找不到,getElementById()将不返回任何节点,而是返回一个空值null , null 表示期望的对象并不存在。
那么,如果我们不能确定文档中是否包含了所需的具有特点ID值的元素,最安全的方法是检测getElementById()返回的是否个节点对象,因为对null值进行操作会导致程序报错或停止运行。
如果你在使用javascript时妨碍了”内容的有效性 和可访问性 “,那么你的做法就是错误的。
给我们的代码加一些验证或检测。
1 | |
2. getElementsByTagName() # 通过标签名称查找元素
如果每次只修改 一个元素,那么使用ID属性查找元素的方法很方便。但是如果需要一次查找一组元素,则getElementsByTagName() 更为合适。
实战:
臃肿的代码:
1 | |
我们需要简化代码:
1 | |
给 getElementsByTagName() 方法的 “ * ”星号参数。
如果把特殊字符串 “*”, 星号通配符 传递给 getElementsByTagName() 方法,它将返回文档中所有元素的列表,元素排列的顺序就是它们在文档中的顺序。
1 | |
注意:
如果你在使用javascript时妨碍了”内容的有效性 和可访问性 “,那么你的做法就是错误的。
我们遇到了浏览器版本问题,那就是IE5.5及更早的IE版本是不支持getElementsByTagName(”*”)。我们现在不排除有些人还在使用古董级的电脑。
你千万别内心里嘀咕,我们开发的外文的网站,是有许多老外还在使用古董级的电脑。不过在IE5.x版本中,Microsoft提供了一个特殊的 document.all对象,该对象包含了文档中的所有元素。因此调用它与调用document.getElementsByTagName(”*”) 的结果是相同的。
范例:
1 | |
根据以上原理,针对上面的例子,写一些兼容性的代码。
范例:
1 | |
注意:
我们在上面的范例中用for 语句 循环输出getElementsByTagName() 方法返回的相同标签名的元素。与getElementById()方法不同的是,即使在文档中没有和指定标签名称相匹配的元素, getElementsByTagName() 方法也会返回一个节点列表。不过节点列表的长度将为0,这就意味着上面范例中用for 语句来检测节点列表长度的语句是可靠地。
3. getElementsByClass() # 通过类名查找元素
注意: getElementsByClass()方法,内建的DOM函数中并没有提供用来实现按类名查找元素的方法,因此我们需要自己动手生产一个函数来完成这一功能。
通过类名查找元素的getElementsByClass()方法,我们在这一章的第二节中,作为一个专题来讨论。