六. W3C DOM之旅的第一步,文档访问

文档对象模型:对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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns= "http://www.w3.org/1999/xhtml" >
<head >
<meta http-equiv = "Content-Type" content = "text/html; charset=utf-8" / >
<title > JavaScript DOM 学习</ title >
</ head >
 
<body >
<h1 > Hello world!</ h1 >
<p >
我是一个WEB前端技术爱好者!
我的WEB前端技术交流网站是
<a href = "http://cssrainbow.cn/" title = "关注WEB前端技术;重视WEB标准 " > CssRainBow.cn</ a >
</ p >
 
</ body >
</ html >

元素节点是DOM节点的一种类型,DOM结构中的大部分节点都是元素节点 ;但在实际的文档中,还包括另外两种节点:文本节点属性节点

节点类型

元素节点

即表示HTML元素的节点。有那些请看 第四章.HTML 4.01/XHTML 1.0 元素列表

文本节点

在HMTL代码中,在成对的尖括号(<>)外的所有内容都会被视为DOM的文本节点。从结构上说,文本节点和元素节点是基本相同的,它们和元素节点同处于树型结构中,也像元素节点那样被访问;但文本节点是没有子节点的。

注意:

文本节点不仅可以包含可见字符,还可以包含一些不可见的字符,例如换行符,tab等符号。

正如我们在例子中看到的代码一样,要使代码更容易与阅读,就需要换行符或TAB符号来分离标签或文本,这样都将被视为一个文本节点对待的

这就意味着相邻的元素之间要用文本节点分隔的,或者在文本节点的开始或结尾处用空白来分离的。不同的浏览器对空白节点的处理方法是不同的,鉴于DOM解析中的这种可变性,处理DOM节点的数目及顺序应格外谨慎。

举例说明:

换行符,tab等符号格式化的代码

1
2
3
4
 <div
 id
=
"test"
>

<h1 > Hello world!</ h1 >
<p > 我是一个WEB前端技术爱好者</ p >
</ div >

为了看出这种区别,我们可以遍历test的子节点,并将其节点个数及节点类型都打印出来:

1
2
3
4
5
var
 x =
 document.getElementById
(
"test"
)
;

var xc = x.childNodes ; //查找子节点
var xcl = xc.length ;
for ( var i= 0 ; i< br /> ");
}

结果:

IE中:

1
2
nodeName =
 H1;
 nodeType =
 1

nodeName = P; nodeType = 1

非IE中:

1
2
3
4
5
nodeName =
 #text;
 nodeType =
 3

nodeName = H1; nodeType = 1
nodeName = #text; nodeType = 3
nodeName = P; nodeType = 1
nodeName = #text; nodeType = 3

两种不同的结果这就是我上面说的原因导致的。

在这种情况下,唯一有可能的原因就是在HTML的书写上,因为这段HTML并不是连续的书写,而是每个节点间都用回车换行了,非IE把换行也当成了一个节点。

连续的书写的HTML

1
 <div
 id
=
"test"
><h1
>
Hello world!</
h1
><p
>
我是一个WEB前端技术爱好者</
p
></
div
>

在IE和非IE中得到了一样的结果

1
2
nodeName =
 H1;
 nodeType =
 1

nodeName = P; nodeType = 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
2
3
4
5
6
7
8
<h1
 id
=
"tit"
>
我是标题一</
h1
>

<p title = "一个段落" > 段落内容放在这里儿!!!!!!!!!!!!</ p >
<strong > 我是无序列表</ strong >
<ul id = "test_ul" >
<li > 列表内容1</ li >
<li > 列表内容2</ li >
<li > 列表内容3</ li >
</ ul >
1
2
3
4
var
 target=
document.getElementById
(
"tit"
)
;

alert ( typeof ( target) ) ; //typeof()判断返回值的类型
alert ( target.innerHTML ) ; //可以获得id为tit对象的内容
alert ( target.nodeName ) ; //返回该节点的标签名称


注意:

我在网页设计时尽量保持元素ID的唯一性。

如果指定的ID值的元素找不到,getElementById()将不返回任何节点,而是返回一个空值null , null 表示期望的对象并不存在。

那么,如果我们不能确定文档中是否包含了所需的具有特点ID值的元素,最安全的方法是检测getElementById()返回的是否个节点对象,因为对null值进行操作会导致程序报错或停止运行。

如果你在使用javascript时妨碍了”内容的有效性可访问性 “,那么你的做法就是错误的。

给我们的代码加一些验证或检测。

1
2
3
4
5
6
7
var
 target=
document.getElementById
(
"tit"
)
;

//判断对象是否存在
if ( target!= null ) {
alert ( typeof ( target) ) ; //typeof()判断返回值的类型
alert ( target.innerHTML ) ; //可以获得id为tit的对象内容
alert ( target.nodeName ) ; //返回该节点的标签名称
}

2. getElementsByTagName() # 通过标签名称查找元素

如果每次只修改 一个元素,那么使用ID属性查找元素的方法很方便。但是如果需要一次查找一组元素,则getElementsByTagName() 更为合适。

实战:

臃肿的代码:

1
2
3
4
5
6
7
alert
(
document.getElementsByTagName
(
"li"
)
.length
)
;
//获得文档中所有的li元素对象的节点数目

//遍历对象
for ( var i= 0 ; i< document.getElementsByTagName ( "li" ) .length ; i++ ) {
alert ( typeof ( document.getElementsByTagName ( "li" ) [ i] ) ) ; //每一个对象的类型
alert ( document.getElementsByTagName ( "li" ) [ i] .innerHTML ) ; //获得每一个对象的值
alert ( document.getElementsByTagName ( "li" ) [ i] .nodeName ) ; // 返回该节点的标签名称
}

我们需要简化代码:

1
2
3
4
5
6
7
var
 items=
document.getElementsByTagName
(
"li"
)
;
//获得文档中所有的li元素对象

//遍历对象
for ( var i= 0 ; i< items.length ; i++ ) {
alert ( typeof items[ i] ) ; //每一个对象的类型
alert ( items[ i] .innerHTML ) ; //获得每一个对象的值
alert ( items[ i] .nodeName ) ; // 返回该节点的标签名称
}

给 getElementsByTagName() 方法的 “ * ”星号参数。
如果把特殊字符串 “*”, 星号通配符 传递给 getElementsByTagName() 方法,它将返回文档中所有元素的列表,元素排列的顺序就是它们在文档中的顺序。

1
2
3
4
5
6
7
8
var
 mylist=
document.getElementById
(
"test_ul"
)
;

var items= mylist.getElementsByTagName ( "*" ) ; //获得ID为“test_ul”的所有子元素对象
//遍历对象。
for ( var i= 0 ; i< items.length ; i++ ) {
alert ( typeof items[ i] ) ; //每一个对象的类型
alert ( items[ i] .innerHTML ) ; //获得每一个对象的值
alert ( items[ i] .nodeName ) ; // 返回该节点的标签名称
}

注意:

如果你在使用javascript时妨碍了”内容的有效性可访问性 “,那么你的做法就是错误的。

我们遇到了浏览器版本问题,那就是IE5.5及更早的IE版本是不支持getElementsByTagName(”*”)。我们现在不排除有些人还在使用古董级的电脑。
你千万别内心里嘀咕,我们开发的外文的网站,是有许多老外还在使用古董级的电脑。不过在IE5.x版本中,Microsoft提供了一个特殊的 document.all对象,该对象包含了文档中的所有元素。因此调用它与调用document.getElementsByTagName(”*”) 的结果是相同的。

范例:

1
2
3
4
5
6
7
8
9
10
11
12
13
var
 elementArray=
[
]
;

if ( typeof document.all != "undefined" ) {
 
elementArray= document.all ; //返回文档中的所有元素
 
} else {
 
elementArray= document.getElementsByTagName ( "*" ) ; //返回文档中的所有元素
 
}
 
//以上代码还可以简化成一下这样
var allArray= document.all ? document.all : document.getElementsByTagName ( "*" ) ;

根据以上原理,针对上面的例子,写一些兼容性的代码。

范例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var
 mylist=
document.getElementById
(
"test_ul"
)
;

var li_all= mylist.all ;
var elementArray= [ ] ;
 
if ( typeof li_all!= "undefined" ) { //检测对象是否存在
// alert("IE5.x的document.all");
elementArray= mylist.all ;
} else {
// alert("非IE5.x的document.all");
elementArray= mylist.getElementsByTagName ( "*" ) ;
}
//遍历对象
for ( var i= 0 ; i< elementArray.length ; i++ ) {
alert ( typeof elementArray[ i] ) ; //每一个对象的类型
alert ( elementArray[ i] .innerHTML ) ; //获得每一个对象的内容
alert ( elementArray[ i] .nodeName ) ; // 返回该节点的标签名称
}

注意:

我们在上面的范例中用for 语句 循环输出getElementsByTagName() 方法返回的相同标签名的元素。与getElementById()方法不同的是,即使在文档中没有和指定标签名称相匹配的元素, getElementsByTagName() 方法也会返回一个节点列表。不过节点列表的长度将为0,这就意味着上面范例中用for 语句来检测节点列表长度的语句是可靠地。

3. getElementsByClass() # 通过类名查找元素

注意: getElementsByClass()方法,内建的DOM函数中并没有提供用来实现按类名查找元素的方法,因此我们需要自己动手生产一个函数来完成这一功能。

通过类名查找元素的getElementsByClass()方法,我们在这一章的第二节中,作为一个专题来讨论。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值