客户端javascript存在使得静态的html文档编程了交互式的web应用。校本化web页面内容是Javascript的核心目标。本章———本书最重要的章节之一,阐述了它是如何做到的客户端javascript的存在使得静态的html文档变成了交互式的web应用。校本化web页面javascript核心目标。本章将阐述它是如何做到的。
第11章和12章解释了每一个web浏览器窗口、标签也和框架由一个window对象所示。每个window对象有一个document对象,document对象表示窗口的内容,它就是本章的主题。尽管如此,Document对象并非独立的,它是一个巨大的API的核心对象,叫做文档对象模型(Document Object Model ,DOM),它代表和操作文档的内容。
本章开始部分解释DOM的基本框架,然后进一步解释以下内容:
本章最后一节涵盖其它各种文档特性,包括referrer属性、write()方法和查询当前文档中选取的文档文本的技术等。
1.DOM概览
文档对象模型(DOM)是表示和操作HTML和xml文档内容的基础API。API不是特别复杂,但是需要了解大量的构架细节。首先:应该理解HTML或XML文档的嵌套元素在DOM树对象中的表示。HTML文档树的结构包含表示HTML标签或元素(如body,<p>)和表示文本字符串的字节,它也可能包含HTML注释的节点。考虑一下简单的HTML文档:
<html> <head> <title>title name</title> </head> <body> <h1>an html Document</h1> <p>this is a <i>simple</i>docuent</p> </body> </html>
此文档DOM,HTML文档的树状表示:
如果还未熟悉计算机编程中的树状结果,借用家谱图形容是比较有用的方法。在一个节点之上的直接节点是其父节点,在其下一层的直接节点是其子节点。在同一层上具有相同父节点的是兄弟及诶单。在一个节点之下的所有层级的一组节点是其后代节点。一个节点任何父节点和其上层的所有节点是祖先节点。
上图的每个方框是文档的一个节点,它表示一个Node对象,我们将在后续几节中讨论Node的属性和方法, 并且可以在第四部分查到这些属性和方法。上图中包含三种类型不同的节点。树行的根部是Document节点,它代表整个文档。 代表HTML元素的节点是Element节点,代表文本的节点是Text节点。Document、Element和Text是Node的子类,在第四部分中它们有自己的条目。Document和Element是两个重要的DOM类,本章大部分内容将删除它们的属性和方法。
下图展示了Node及其在类型层次结构中的子类型。注意,通用的Document和Element类型与HTMLDocument和HTMLElement类型之间有严格的区别。Document类型代表一个HTML或XML文档 ,Element类型代表了该文档中的一个元素。HTMLDocument和HTMLElement子类只是征对于HTML文档和元素。此书中,我们经常使用类名Document和Element,甚至在指代HTML文档时也不例外。在第四部分也是如此:HTMLDocument和HTMLElement类型 属性和方法记录于Document和Element参考页中。
上文的每个方框是文档的一个节点,它表示一个Node对象,我们将在后续几节中讨论Node的属性和方法, 并且可以在第四部分查到这些属性和方法。上图中包含三种类型不同的节点。树行的根部是Document节点,它代表整个文档。 代表HTML元素的节点是Element节点,代表文本的节点是Text节点。Document、Element和Text是Node的子类,在第四部分中它们有自己的条目。Document和Element是两个重要的DOM类,本章大部分内容将删除它们的属性和方法。
下图展示了Node及其在类型层次结构中的子类型。注意,通用的Document和Element类型与HTMLDocument和HTMLElement类型之间有严格的区别。Document类型代表一个HTML或XML文档 ,Element类型代表了该文档中的一个元素。HTMLDocument和HTMLElement子类只是征对于HTML文档和元素。此书中,我们经常使用类名Document和Element,甚至在指代HTML文档时也不例外。在第四部分也是如此:HTMLDocument和HTMLElement类型 属性和方法记录于Document和Element参考页中。
文档节点的部分层次结构:
值得注意的是,上图中HTMLElement的很多子类型代表HTML元素的具体类型。每个类型定义多个javascript属性,它们对应具体的元素或元素组,(本章4.i节)的HTML属性。有些具体元素也定义额外的属性和方法,它们并不是简单地映射HTML语法。第四部分涵盖这些类型及其额外的特性。
最后,上图还展示了到目前还未接触的一些节点类型,Conmment节点代表HTML或XML的注释。由于注释基本上是文本字符串,因此它们很像表示文档中显式文本的Text节点。CharacterData通常是Text和Conmment的祖先,它定义这两种节点所共享的方法。Attr节点类型代表XML或HTML属性,但它几乎从不使用,因为和文档节点不同,Element类型定义了将属性当做“名/值”对使用方法。DocumentFragment类(未在上图显式)在实际文档中并不存在的一种节点:它代表一系列没有常规父节点的节点,对一些文档操作来说DocumentFragment非常有用,本章6.iiii将涵盖这部分内容。DOM也定义了一些不常使用的类型,如像代表Doctype声明和xml处理指令等类型。
2.选取文档元素
大多数客户端javascript程序运行时总是在操作一个或多个文档元素,这些程序启动时,可以使用全局变量document来引用Document对象。但是,为了操作文档中的元素,必须通过某种方式来获得或选取这些文档元素的Element对象,DOM定义了很多方式来选取元素,查询文档的一个或多个元素有如下的方法:
随后几节将解释每一种元素选取技术
i.通过id选取元素
任何HTML元素可以有一个id属性,在文档中值必须唯一,即同一个文档中两个元素不能有相同的ID。可以用Document对象的getElementById()方法选取一个基于唯一ID的元素,此方法我们在11章和12章都说明过了:
var section1 = document.getElementById("section1")
这就是最简单和常用的选取元素的方法。如果想要操作一组指定的文档元素,提供这些元素的id属性,并且使用ID查找这些Element对象。
如果需要通过ID查找多个元素,会发现下面的例子getElements()函数非常有用:
/** * 函数接受任意多的字符串参数 * 每个参数将当做元素的id传给document.getElementById() * 返回一个对象,它把这些id映射到对应的Element对象 * 如任何一个id对应的元素未定义,则抛出一个Error对象 **/ function getElement( /*ID(s)*/ ) { var elements = {}; //开始是一个map映射对象 for (var i = 0; arguments.length; i++) { //循环每个参数 var id = arguments[i]; //参数是元素的id var elt = document.getElementById(id); //查找元素 if (elt == null) throw new Error("No element with id: " + id); //抛出异常 elements[id] = elt; //id和元素之间的映射 } return elements; //对于元素映射返回id }
在低于IE8版本的浏览器中,getElementById()对匹配元素不区分大小写,而且也返回匹配name属性的元素。
ii.通过name名字获取元素
HTML的name属性最初打算为表单元素分配名字,在表单数据提交到服务器时使用该属性的值。类似id属性,name是给元素分配的名字,但是区别id,name的属性值不是必须唯一:多个元素可能有同样的名字,在表单中,单选和复选按钮通常是这样的情况。而且和id不一样的是name属性值是在少数HTML元素中有效,包括表单、表单元素、<iframe>和<img>元素。
基于name属性的值选取html元素,可以使用Document对象的getElementByName()方法。
var radiobuttons = document.getElementsByName("favorite_color");
getElementsByName()定义在HTMLDocument类中,而不在Document类中,所有它只征对HTML文档可用,在xml文档中不可用。它返回一个NodeList对象,后者的行为类似若干Element对象的只读数组。在IE中,getElementByname()也返回id属性匹配中只读的元素。为了兼容,应该小心谨慎,不要将ID和name同名。
在12章7节中我们看到,为某些HTML元素设置name属性将自动为window对象中创建对于的属性,对Document对象也类似。为<form><img><iframe><applet><embed><object>元素(其中只有<object>元素没有后背对象)设置name属性值, 即在Document对象中创建以此name属性值为名字的属性。
如果给定的名字只有一个元素,自动创建的文档属性对于的值该是元素本身。如果有多个元素,该文档属性的值是一个NodeList对象,它表现为一个包含这些元素的数组。如12章7节所示,为若干命名<iframes>元素创建的文档属性比较特殊:它们指代这些框架的window对象而不是Element对象。这就意味这有些元素可以作为Document属性仅通过名字来选取:
//征对<form name="shipping">元素,得到Element对象 var form = document.shipping;
在14章7节介绍了为什么不要用为窗口对象自动创建的属性,这同样适用用为文档对象自动创建的属性。如果需要查找命名的元素,最好显式地调用getElementByName()来查找它们。
iii.通过标签名选取元素
Document对象的getElementsByTagName()方法可用来选取指定类型(标签名)的所有HTML或XML元素。例如,如下代码,在文档中获得包含所有<span>元素的只读类数组对象。
var spans = document.getElementsByTagName("span");
类似于getElementByName(),getElementByTagName()返回一个NodeList对象(关于NodeList类,见本节补充的信息)。在NodeList中返回的元素按照在文档中的顺序排序的,所有可用如下代码选取文档中的第一个p元素
var firstspan = document.getElementsByTagName("span")[0];
<html>标签是不区分大小写的,在HTML文档中使用getElementsByTagName()时,它进行不区分大小写的标签名比较。例如,上述的变量span将包含所有写成<SPAN>的span标签。
给getElementByTagName()传递通配符参数"*"将获得一个代表文档中所愿元素的NodeList对象。
Element定义getElementByTagName()方法,其原理和Document版本一样,但是它只选取调用该方法的元素的后代元素。因此,要查找文档的第一个<p>元素里所有<span>元素,代码如下:
var firstpara = document.getElementsByTagName("p")[0]; var firstParaspan = firstpara.getElementsByTagName("span");
由于历史的原因,HTMLDocument类定义的一些快捷属性来访问各种各样的节点。例如images、forms和links等属性行为执行类似只读数组<img>、<from>和><a>(但只包含哪些有href属性的<a>标签)元素结合。这些属性指代HTMLCollection对象,它们很像NodeList对象,但是除此之外它们可以用元素的id或名字来索引,我们已经看到用法如下的表达式来索引一个命名的<form>元素:
document.shiping;
用document.forms属性也可以更具体地引用命名(或有ID)表单,如下:
document.forms.shipping
HTMLDocument对象还定义两个属性,它们指代包含特殊的单个元素而不是元素的集合。document.body是一个HTML文档的 <body>元素,document.head是<head>元素,浏览器隐式地创建它们。Document类的documentElement属性指代文档的根元素,在HTML文档中,它总指代<HTML>元素。
节点列表和HTML集合
节点列表和HTML集合 getElementByName()和getElementByTagName()都返回NodeList对象,类似document.images和document.forms的属性为HTMLCollection对象 这些对象都是只读的类数组对象(7章11节),它们有length属性,也可以像正真的数组一样所有(只是读而不写),可以对一个NodeList或HTMLCollection的内容用如下标准的循环进行迭代:
for (var i = 0; i < document.images.length; i++) //循环所有的图片 document.images[i].style.display = "none";
不能直接在NodeList和HTML集合上调用Array的方法,但可以间接地使用:
var content Array.PRototype.map.call(document.getElementsByTagName("p"),function(e){return e.innerHTML;});
HTMLCollection对象也有额外的命名属性,也可以通过数字和字符串来索引。
由于历史元素,NodeList和HTMLCollection对象也都能当做函数:以数字或字符串为参数调用它就如同使用数字或字符串索引它们一般,不鼓励这种怪异的方法。
NodeList和HTMLCollection对象也都能当做函数都不是为像javascript这样的动态语言设计的。它们都定义了item()方法,期望输入一个整数,并返回
新闻热点
疑难解答