JavaScriptDOM编程艺术读书笔记(3)

来源:互联网 发布:淘宝直播怎么私信主播 编辑:程序博客网 时间:2024/05/21 19:36
  第3章DOM
本章内容
节点的概念
四个非常实用的DOM方法:getElementById,getElementsByTagName,getAttribute和setAttribute
3.1        文档:DOM中的“D”
DOM是“Document Object Model”的首字母缩写。如果没有document(文档),DOM也就无从谈起。当创建了一个网页并把它加载到Web浏览器中时,DOM就在幕后悄然而生。浏览器将根据你编写的网页文档创建一个文档对象。<script type="text/javascript"><!--google_ad_client = "pub-3269163127493396";google_ad_width = 468;google_ad_height = 60;google_ad_format = "468x60_as";google_ad_type = "text_image";//2007-10-05: ITgoogle_ad_channel = "0064192373";google_ui_features = "rc:6";//--></script> <script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
3.2        对象:DOM中的“O”
我们向大家展示了几个JavaScript对象的例子。你们应该还记得,“对象”是一种独立的数据集合。与某个特定对象相关联的变量被称为这个对象的属性;可以通过某个特定对象去调用的函数被称为这个对象的方法。
JavaScript语言里的对象可以分为三种类型:
用户定义对象(user-defined object):由程序员自行创建的对象。本书不讨论这种对象。
内建对象(native object):内建在JavaScript语言里的对象,如Array,Math和Date等。
宿主对象(host object):由浏览器提供的对象。
本书注意力将集中在浏览器窗口的内部而不是浏览器窗口本身。我们将着重探讨如何对网页内容进行处理,而用来实现这一目标的载体就是document对象。
3.3        模型:DOM中的“M”
它的含义是某种事物的表现形式。就像一个模型火车代表着一列真正的火车,一张城市街道图代表着一个实际存在的城市那样,DOM代表着被加载到浏览器窗口里的当前网页:浏览器向我们提供了当前网页的地图(或者是模型,英文里这两个单词均以M打头),而我们可以通过JavaScript去读取这个模型。
要想看懂和使用地图,就必须知道这些记号的含义和用途——这个道理同样适用于DOM。要想从DOM获得信息,我们必须先把各种用来表示和描述一份文档的记号弄明白。
DOM把一份文档表示为一棵树(这里所说的“树”是数学意义上的概念),这是我们理解和运用这一模型的关键。更具体地说,DOM把文档表示为一棵家谱树。
家谱树的典型用法是表示一个人类家族的谱系并使用parent(父),child(子),sibling(兄弟)等记号来表明家族成员之间的关系。家谱树可以把一些相当复杂的关系简明地表示出来:一位特定的家族成员既是某些成员的父辈,又是另一位成员的子辈,同时还是另一位成员的兄弟。
家谱树模型也非常适合用来表示一份用(X)HTML语言编写出来的文档。
请看下面这份非常基本的网页,它的内容是一份购物清单。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
         <head>
                   <meta http-equiv="content-type" content="text/html;charset=utf-8" />
                   <title>Shopping list</title>
         </head>
         <body>
                   <h1>What to buy</h1>
                   <p title="a gentle reminder">Don't forget to buy this stuff.</p>
                   <ul id="purchases">
                            <li>A tin of beans</li>
                            <li>Cheese</li>
                            <li>Milk</li>
                   </ul>
         </body>
</html>
这份文档可以用图3-1来表示。

 
                   html
                    |
         -------------------------
         |                                   |
         head                            body
          |                           |
     ------------          -------------------------
     |              |       |        |            |
    meta   title  h1    p            ul
                                                        -----------------
                                                        |       |       |
                                                        li       li       li
         图3-1 把网页中的元素表示为一棵家谱树
我们来分析一下这个网页的结构。在对DOCTYPE做出声明后,这份文档首先打开了一个<html>标签,而这个网页里的所有其他元素都包含在这个元素里。因为所有其他的元素都包含在其内部,所以这个<html>标签既没有父辈,也没有兄弟。如果这是一棵真正的树的话,这个<html>标签显然就是树根。
如果在这份文档里更深入一层,我们将发现<head>和<body>两个分枝。它们存在于同一层次且互不包含,所以它们是兄弟关系。它们有着共同的父元素<html>,但又各有各的子元素,所以它们本身又是其他一些元素的父元素。
利用这种简单的家谱关系记号,我们可以把各元素之间的关系简明清晰地表达出来。
例如,<h1>和<ul>之间是什么关系?答案是它们是兄弟关系。
那么<body>和<ul>之间又是什么关系?<body>是<ul>的父元素,<ul>是<body>的一个子元素。
如果把各种文档元素想像成一棵家谱树上的各个节点的话,我们就可以用同样的记号来描述DOM。不过,与使用“家谱树”这个术语相比,把一份文档称为一棵“节点树”更准确。
    3.3.1       节点
节点(node)这个名词来自网络理论,它代表着网络的连接点。网络是由节点构成的集合。
在现实世界中,一切事物都由原子构成。原子就是现实世界的节点。
DOM也是同样的情况。文档也是由节点构成的集合,只不过此时的节点是文档树上的树枝和树叶而已。
在DOM里存在着许多不同类型的节点。就像原子包含着亚原子微粒那样,有些DOM节点类型还包含着其他类型的节点。
1.元素节点
DOM的原子是元素节点(element node)。
如果把Web上的文档比作一座大厦,元素就是建造这座大厦的砖块,这些元素在文档中的布局形成了文档的结构。
标签提供了元素的名字,如文本段落元素的名字是“p”,无序清单元素的名字是“ul”,等等。
元素可以包含其他的元素。如前面的“购物清单”文档里,所有的清单项元素都包含在一个无序清单元素的内部。
2.文本节点
如果一份文档完全由一些空白元素构成,它将有一个结构,但这份文档本身将不会包含什么内容。在网上,内容决定着一切,没有内容的文档是没有任何价值的,而绝大多数内容都是由文本提供的。
在“购物清单”例子里,p元素包含着文本“Don't forget to buy this stuff.”。这是一个文本节点(text node)。
在XHTML文档里,文本节点总是被包含在元素节点的内部。但并非所有的元素节点都包含有文本节点。在“购物清单”文档里,<ul>元素没有直接包含任何文本节点——它包含着其他的元素节点(一些<li>元素),后者包含着文本节点。
3.属性节点
元素都或多或少地有一些属性,属性的作用是对元素做出更具体的描述。例如,几乎所有的元素都有一个title属性,而我们可以利用这个属性对包含在元素里的东西做出准确的描述:
<p title="a gentle reminder">Don't forget to buy this stuff.</p>
在DOM中,title="a gentle reminder"是一个属性节点(attribute node),因为属性总是被放在起始标签里,所以属性节点总是被包含在元素节点当中。
4.CSS:层叠样式表
DOM并不是人们与网页的结构打交道的唯一手段。我们还可以通过CSS(层叠样式表)告诉浏览器应该如何显示一份文档的内容。
类似于JavaScript脚本,对样式的声明既可以嵌在文档的<head>部分(这需要用到<style>标签),也可以放在另外一个样式表文件里。利用CSS对某个元素的样式做出声明的语法与JavaScript函数的定义语法很相似:
selector{
         property:value;
}
在样式声明里,我们可以对浏览器在显示各有关元素时使用颜色,字体和字号做出定义,如下所示:
p{
         color:yellow;
         "arial",sans-serif;
         font-size:1.2em;
}
继承(inheritance)是CSS技术中的一项强大功能。类似于DOM,CSS也把文档的内容视为一棵节点树。节点树上的各个元素将继承其元素的样式属性。
例如,如果我们为body元素定义了一些颜色或字体,包含在body元素里的所有元素都将自动获得——也就是继承——那些样式:
body{
         color:white;
         background-color:black;
}
这些颜色将不仅作用于那些被直接包含在<body>标签里的内容,还将作用于那些嵌套在body元素内部的所有元素。
在某些场合,当把样式应用于一份文档时,我们其实只想让那些样式只作用于某个特定的元素。例如,我们只想让某一段文本变成某种特殊的颜色和字体,但不想让其他段落受到影响。为了获得如此精细的控制,我们将需要在文档里插入一些能够把这段文本与其他段落区别开来的特殊标志。
为了把某一个或某几个元素与其他元素区别开来,我们需要使用class属性或id属性之一。
Ø class属性
所有的元素都有class属性,不同的元素可以有同样的class属性值。如下所示:
<p class="special">This paragraph has the special class</p>
<h2 class="special">So does this headline</h2>
在样式表里,我们可以像下面这样为class属性值相同的所有元素定义一种共享的样式:
.special{
         font-style:italic;
}
我们还可以像下面这样利用class属性为一种特定类型的元素定义一种独享的样式:
h2.special{
         text-transform:uppercase;
}
Ø id属性
id属性的用途是给网页里的某个元素加上一个独一无二的标识符,如下所示:
#purchases{
         border:1px solid white;
         background-color:#333;
         color:#ccc;
         padding:1em;
}
每个元素只能有一个id属性值,不同的元素必须有不同的id属性值。不过,我们可以在样式表里像下面这样,利用id属性为包含在某给定元素里的其他元素定义样式,而如此定义出来的样式将只作用于包含在这个给定元素里的有关元素:
#purchases li{
         font-weight:bold;
}
 
默然说话:关于id是一个独一无二的标识符这一点,浏览器似乎并没有进行验证。也就是说,其实我们可以让两个元素的id属性是相同的,我不知道这意味着什么。不过我想,我们还是应该自觉遵守“id是一个独一无二的标识符”这条规则吧?
    3.3.2       getElementById()方法
DOM提供了一个名为getElementById()的方法,这个方法将返回一个与那个有着给定id属性值的元素节点相对应的对象。请注意,JavaScript语言区分字母大小写,所以大家在写出“getElementById”时千万不要把大小写弄错了。
这个方法是与document对象相关联的函数。在脚本代码里,函数名的后面必须跟有一组圆括号,这组圆括号包含着函数的参数。getElementById()方法只有一个参数:你想获得的那个元素的id属性值,这个id值必须放在单引号或双引号里。
document.getElementById(id)
下面是一个例子:
document.getElementById("purchases")
这个调用将返回一个对象,这个对象对应着document对象里的一个独一无二的元素,那个元素的HTML id属性值是purchases。再说一遍,getElementById()方法将返回一个对象。你们可以用typeof操作符来验证这一点。typeof操作符可以告诉我们它的操作数是不是一个字符串,数值,函数,布尔值或对象。
下面是把一些JavaScript语句插入到前面给出的“购物清单”文档之后得到的一份代码清单,新增的代码(黑体部分)出现在</body>结束标签之前。顺便说一句,我本人并不赞成把JavaScript代码直接嵌入一份文档的做法,但它不失为一种简便快捷的测试手段:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
         <head>
                   <meta http-equiv="content-type" content="text/html;charset=utf-8" />
                   <title>Shopping list</title>
                   <style>
                            p{
                                     color:yellow;
                                     "arial",sans-serif;
                                     font-size:1.2em;
                            }
 
                            body{
                                     color:white;
                                     background-color:black;
                            }
                            #purchases{
                                     border:1px solid white;
                                     background-color:#333;
                                     color:#ccc;
                                     padding:1em;
                            }
                   </style>
         </head>
         <body>
                   <h1>What to buy</h1>
                   <p title="a gentle reminder">Don't forget to buy this stuff.</p>
                   <ul id="purchases">
                            <li>A tin of beans</li>
                            <li>Cheese</li>
                            <li>Milk</li>
                   </ul>
                  
                   <script type="text/javascript">
                            alert(typeof document.getElementById("purchases"));
                   </script>
         </body>
</html>
当在你的Web浏览器里加载这个XHTML文件时,屏幕上将弹出一个如下所示的alter对话框,它向你们报告document.getElementById("purchases")的类型——它是一个对象。
事实上,文档中的每一个元素都对应着一个对象。利用DOM提供的方法,我们可以把与这些元素相对应的任何一个出来。
一般来说,我们用不着为文档里的每一个元素都分别定义一个独一无二的id值:那也太小题大作了。要知道,即使某个元素没有独一无二的id,我们也可以利用DOM提供的另一个方法把与之对应的对象准确无误地筛选出来。   
3.3.3       getElementsByTagName()方法
getElementsByTagName()方法将返回一个对象数组,每个对象分别对应着文档里有着给定标签的一个元素。类似于getELementById(),这个方法也是只有一个参数的函数。它的参数是(X)HTML标签的名字:
element.getElementsByTagName(tag)
有一点要特别提醒大家注意:getElementsByTagName()方法返回的是一个数组;你们在编写脚本时千万注意不要把这两个方法弄混了。
下面是一个例子:
document.getElementsByTagName("li")
这个调用将返回一个对象数组,每个对象分别对应着docuement对象中的一个清单项(li)元素。
与任何数组一样,我们可以利用length属性查出这个数组里的元素个数。
我们可以试试下面这个for循环:
for(var i=0;i<doucment.getElementsByTagName("li").length;i++){
         alert(typeof document.getElementsByTagName("li")[i]);
}
请注意,即使在整个文档中只有一个元素有着给定的标签名,getElementsByTagName()方法也将返回一个数组。此时,那个数组的长度是1。
我们其实可以把document.getElementsByTagName("li")赋值给一个变量,就可以不用反复敲入getElementsByTagName("li")了。
请在上一小节给出的XHTML示例文档里把<script>标签中的alert语句替换为下面这些语句:
var items=document.getElementsByTagName("li");
for(var i=0;i<items.length;i++){
         alert(typeof items[i]);
}
现在,当用浏览器重新加载那个XHTML文件时,你们将看到三个alert对话框,显示在这三个alert对话框里的消息都是“object”。
getElementsByTagName()允许我们把一个通配符当为它的参数,而这意味着文档里的每个元素都将在这个函数所返回的数组里占有一席之地。通配符(星号字符"*")必须放在引号里,这是为了让通配符与乘法操作符有所区别。如果你想知道某份文档里总共有多少个元素节点,像下面这样以通配符为参数去调用getElementsByTagName()方法是最简便的办法:
alert(document.getElementsByTagName("*").length);
3.4        趁热打铁
在看过那么多显示着单词“object”的alert对话框后,你们很可能不愿意再看到它。如果真是如此,我的目的也就达到了——我想通过这些alert对话框强调这样一个事实:文档中的每个元素节点都是一个对象。我现在要告诉大家的是,这些对象中的每个都为我们准备了一系列非常有用的方法,而这一切当然都要归功于DOM。利用这些已经预先定义好的方法,我们不仅可以检索出关于文档里的任何一个对象的信息,甚至还可以改变某些元素的属性。
下面是对本章此前学习内容的一个简要总结:
一份文档就是一棵节点树。
节点分为不同的类型:元素节点,属性节点和文本节点等。
getElementById()方法将返回一个对象,该对象对应着文档里的一个特定的元素节点。
getElementsByTagName()方法将返回一个对象数组,它们分别对应着文档里的一个特定的元素节点。
这些节点中的每个都是一个对象。
    3.4.1       getAttribute()方法
getAttribute()方法是一个函数。它只有一个参数——你打算查询的属性的名字:
object.getAttribute(attribute)
不过,getAttribute()方法不能通过document对象调用,这与我们此前介绍过的其他方法不同。我们只能通过一个元素节点对象调用它。
例如,你可以把它与getElementsByTagName()方法结合起来,去查询每个<p>元素的title属性,如下所示:
var paras=document.getElementsByTagName("p");
for(var i=0;i<paras.length;i++){
         alert(paras[i].getAttribute("title"))
}
如果把上面这段代码插入到前面给出的“购物清单”示例文档的未尾,并在Web浏览器里重新加载这个页面,屏幕上将弹出一个显示着文本消息“a gentle reminder”的alert对话框。
在“购物清单”文档里只有一个带有title属性的<p>元素。假如这份文档还有一个或者更多个不带title属性的<p>元素,则相应的getAttribute("title")调用将返回null。null是JavaScript语言中的空值,其含义是“你说的这个东西不存在”。
可以修改我们的脚本,让它只在title属性存在时才弹出一条消息,我们将增加一条if语句来检查getAttribute()方法的返回是不是null。趁着这个机会,我们还增加了几个变量以提高脚本的可读性:
var paras=document.getElementsByTagName("p");
for(var i=0;i<paras.length;i++){
         var title_text=paras[i].getAttribute("title");
         if(title_text!=null){
                   alert(title_text);
         }
}
现在,如果重新加载这个页,你们将只会看到一个显示着“a gentle reminder”消息的alert对话框,如下所示。
(默然说话:本人在IE下面验证了上面的代码,结果发现仍然会弹出两个对话框,没加title属性的那个<p>弹出的是一个什么也没写的alert框,把if语句改为if(title_text!="")才能得到文章中描述的结果。而在firefox下面,上面的语句才是正确的,其中一个alert对话框也显示了null)
我们甚至可以把这段代码缩得更短一些。当检查某项数据是否是null值时,我们其实是在检查它是否存在。这种检查可以简化为直接把被检查的数据用做if语句的条件。
具体到这个例子,只要我们把if(title_text!=null)替换为if(title_text),我们就可以得到更简明的代码。(默然说话:这样写法带来的另一个副作用是:IEfirefox下的运行效果一致了,因为""nullif测试结果均为false)   
3.4.2       setAttribute()方法
我们此前介绍给大家的所有方法都只能用来检索信息。setAttribute()方法与它们有一个本质上的区别:它允许我们对属性节点的值做出修改。
类似于getAttribute()方法,setAttribute()方法也是一个只能通过元素节点对象调用的函数,但setAttribute()方法需要我们向它传递两个参数:
object.setAttribute(attribute,value)
在下面的例子里,第一条语句将把id属性值是purchase的元素检索出来,第二条语句将把这个元素的title属性值为a list of goods:
var shopping=document.getElementById("purchase");
alert(shopping.getAttribute("title"));
shopping.setAttribute("title","a list of goods");
alert(shopping.getAttribute("title"));
在上例中,我们设置了一个现有节点的title属性,但这个属性原先并不存在。这意味着我们发出的setAttribute()调用实际完成了两项操作:先把这个属性创建出来,然后再对其值进行设置。如果我们把setAttribute()方法用来元素节点的某个现有属性上,这个属性的当前值将被覆盖。
<script type="text/javascript"><!--google_ad_client = "pub-3269163127493396";google_ad_width = 468;google_ad_height = 60;google_ad_format = "468x60_as";google_ad_type = "text_image";//2007-10-05: ITgoogle_ad_channel = "0064192373";google_ui_features = "rc:6";//--></script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
在“购物清单”示例文档里,<p>元素已经有了一个title属性,这个属性的值是a gentle reminder。我们可以用setAttribute()方法来改变它的当前值:
var paras=document.getElementsByTagName("p");
for(var i=0;i<paras.length;i++){
         var title_text=paras[i].getAttribute("title");
         if(title_text){
                   paras[i].setAttribute("title","brand new title text");
                   alert(paras[i].getAttribute("title"));
         }
}
上面这段代码将先从文档里把已经带有title属性的<p>元素全部检索出来,然后有title属性的元素才修改它的title属性值。全部修改为brand new title text。具体到“购物清单”文档,属性值a gentle reminder将被覆盖。
这里有一个非常值得关注的细节:通过setAttribute()方法对文档做出的修改,将使得文档在浏览器窗口里显示效果和/或行为动作发生相应的变化,但我们在通过浏览器的view source(查看源代码)选项去查看文档的源代码时看到的仍将是原来的属性值——也就是说,setAttribute()方法做出的修改不会反映在文档本身的源代码里。这种“表里不一”的现象源自DOM的工作模式:先加载文档的静态内容,再以动态方式对它们进行刷新,动态刷新不影响文档的静态内容。这正是DOM的真正威力和诱人之处:对页面内容的刷新不需要最终用户在他们的浏览器里执行页面刷新操作就可以实现。
3.5        小结
在这一章里,我们向大家介绍了DOM提供的四个方法:
getElementById()方法
getElementsByTagName()方法
getAttribute()方法
setAttribute()方法
这四个方法是将要编写的许多DOM脚本的基石。
DOM还提供了许多其他的属性和方法,如nodeName,nodeValue,chileNodes,nextSibling和parentNode等,但现在还不是它们出场的时候——我打算在本书后面的有关章节中选择一些适当的时机把它们依次介绍给大家。我在这里列出它们的目的只是为了激起大家的学习兴趣。
本章内容比较偏重于理论。在看过那么多的alert对话框之后,相信大家都迫不及待地想通过其他一些东西去进一步了解和测试DOM,而我也正想通过一个案例来进一步展示DOM的强大威力。
在下一章中,我将带领大家利用本章介绍的四个DOM方法去创建一个基于JavaScript的图片库。

 

<script type="text/javascript"><!--google_ad_client = "pub-3269163127493396";google_ad_width = 468;google_ad_height = 60;google_ad_format = "468x60_as";google_ad_type = "text_image";//2007-10-05: ITgoogle_ad_channel = "0064192373";google_ui_features = "rc:6";//--></script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>

您好:
    当您在阅读和使用我所提供的各种内容的时候,我非常感谢,您的阅读已是对我最大的支持。
    我更希望您能给予我更多的支持。
    1.希望您帮助我宣传我的博客,让更多的人知道它,从中获益(别忘记了提醒他们帮我点点广告,嘿嘿)。
    2.希望您能多提出宝贵意见,包括我所提供的内容中的错误,建设性的意见,更希望获得哪些方面的帮助,您的经验之谈等等。
    3.更希望能得到您经济上的支持。
   
    我博客上面的内容均属于个人的经验,所有的内容均为开源内容,允许您用于任何非商业用途,并不以付费为前提,如果您觉得在阅读和使用我所提供的各种内容的过程中,您得到了帮助,并能在经济上给予我支持,我将感激不尽。

    您可以通过点击我网站上的广告表示对我的支持。

    您可以通过银行转帐付款给我:
    招商银行一卡通:
    卡号:6225888712586894
    姓名:牟勇
   
    您也可以通过汇款的方式:
    通讯地址:云南省昆明市女子(28)中学人民中路如意巷1号
    收信人:陈谦转牟勇收
    邮编:650021
   
    无论您给予我怎么样的支持,我都衷心的再次感谢。
    欢迎光临我的博客,欢迎宣传我的博客
    http://blog.csdn.net/mouyong
    http://blog.sina.com.cn/mouyong
    EMail:mouyong@yeah.net
    QQ:11167603
    MSN:mouyong1973@hotmail.com

原创粉丝点击