DOM概览

文档对象模型(DOM)是表示和操作HTML和XML文档的基础API。

选取文档元素

DOM定义许多方式来选取元素,查询文档的一个或多个元素有如下方法:
1、用指定的id属性;
2、用指定的name属性;
3、用指定的标签名字;
4、用指定的CSS类;
5、匹配指定的CSS选择器。

通过ID选取元素

任何HTML元素可以有一个id属性,在文档中该值必须唯一,即同一个文档中的两个元素不能用相同的ID。可以用Document对象的getElementById()方法选取一个基于唯一ID的元素。
在低于IE 8版本的浏览器中,getElementById()对匹配元素的ID不区分大小写,而且也返回匹配name属性的元素。

通过名字选取元素

HTML的name属性最初打算为表单元素分配名字,在表单数据提交到服务器时使用该属性的值。类似id属性,name是给元素分配名字,但是区别以id,name属性的值不是必须唯一:多个元素可能有同样的名字,在表单中,单选和复选按钮通常是这种情况。而且,和id不一样的是name属性只在少数HTML元素中有效,包括表单、表单元素.

通过标签名选取元素

Document对象的getElementsByTagName()方法可用来选取指定类型(标签名)的所有HTML或XML元素。
类似于getElementsByName(),getElementsByTagName()返回一个NodeList对象。在NodeList中返回的元素按照在文档中的顺序排序。

HTML标签式不区分大小写的,当在HTML文档中使用getElementsByTagName()时,它进行不区分大小写的标签名比较。

Element类也定义getElementsByTagName()方法,其原理和Document版本的一样,但是只选取调用该方法的元素的后代元素。因此,要查找文档中第一个

元素里面的所有,代码如下:

var firstpara = document.getElementsByTagName(“p”)[0];
var firstParaSpans = firstpara.getElementsByTagName(“span”);

HTMLDocument类定义一些快捷属性来访问各种各样的节点。例如,images,forms和links等属性指向行为类似只读数组的<img>,<form>和<a>(但只包含哪些有href属性<a>的标签)元素集合。这些属性指代HTMLCollection对象,它们很像NodeList对象,但是除此之外它们可以用元素的ID或名字来索引。HTMLDocument对象还定义两个属性,它们指代特殊的单个元素而不是元素的集合。document.body是一个HTML文档的<body>元素,document.head是<head>元素。这些属性总是会定义:如果文档源代码未显式的包含<head>和<body>元素,浏览器将阴式的创建它们。Document类的documentElement属性指代文档的根元素。在HTML文档中,它总是指代<html>元素。

节点列表和HTML集合

getElementsByName()和getElementsByTagName()都返回NodeList对象,而类似document.images和document.forms的属性为HTMLCollection对象。

这些对象都是只读的类数组对象。它们有length属性,也可以象真正的数组一样索引,可以对一个NodeList或HTMLColleciton的内容用如下表转的循环进行迭代:
for(var I = 0; I < document.images.length; i++) //循环所有的图片
document.images[i].style.display = “none”;//隐藏

文档结构和遍历

作为节点数的文档

Document对象、它的Element对象和文档中表示文本的Text对象都是Node对象。Node定义了一下重要的属性
parentNode:该节点的父节点,或者针对类似Document对象应该是null,因为无父节点
childNodes:只读的类数组对象(NodeList对象),它是该节点的子节点的实时表示。
firstChild、lastChild:该节点的子节点中的第一个和最后一个,如果该节点没有子节点则为null。
nextSibling、previoursSibling:该节点的兄弟节点中的前一个和下一个。具有相同父节点的两个节点为兄弟节点。节点的顺序反映了它们在文档中出现的顺序。这两个属性将节点之间以双向链表的形式连接起来。
nodeType:该节点的类型。9代表Document节点,1代表Element节点,3代表Text节点,8代表Comment节点,11代表DocumentFragment节点。
nodeValue:Text节点或Comment节点的文本内容。
nodeName:元素的标签名,以大写形式表示。

作为元素树的文档

firstElementChild,lastElementChild类似firstChild和lastChild,但只代表Element。
nextElementSibling,previousElementSibling,类似nextSibling和previousSibling,但只代表兄弟Element。
childElementCount:子元素的数量。返回值和children.length值相等。

属性

HTML元素由一个标签和一组称为属性的名/值对组成。

HTML属性作为Element的属性

表示HTML文档元素的HTMLElement对象定义了读/写属性,他们映射了元素的HTML属性。HTMLElement定义了通用的HTTP属性(id,标题lang和dir)的属性,以及事件处理程序属性。
HTML属性名不区分大小写,但JavaScript属性名则大小写敏感。从HTML属性名转换到JavaScript属性名应该采用小写。但是,如果属性名包含不止一个单词,则将除了第一个单词以外的单词的首字母大写。
表示HTML属性的值通常是字符串。当属性为布尔值或数值,属性也是布尔值或数值,而不是字符串。事件处理程序属性值总是为Function对象。任何HTML元素的style属性值是CSSStyleDeclaration对象,而不是字符串。

获取和设置非标准的HTML属性。

Element类型还定义了getAttribute()和setAttribute()方法来查询和设置非标准的HTML属性,也可用来查询和设置XML文档中元素上的属性。
var image = document.images[0];
var width = parseInt(image.getAttribute(“WIDTH”));
image.setAttribute(“class”,”thumbnail”);
上述代码给出了这些方法和前面的基于属性的API之间的两个重要的区别。首先,属性值都被看做是字符串。getAttribute()不返回数值、布尔值或对象。其次,方法是用标准属性名,甚至当这些名称为JavaScript保留字时也不例外。对HTML元素来说,属性名不区分大小写。
Element类型还定义了两个相关的方法,hasAttribute()和removeAttribute(),它们用来检测命名属性是否存在和完全删除属性。

数据集属性

在HTML元素上绑定一些额外的信息是很有帮助的,当JavaScript选取这些元素并以某种方式操纵这些信息时就是很典型的情况,有时可以通过class属性添加特殊的标识符来完成。其他时候针对更复杂的数据,客户端程序员会借助使用非标准的属性。可以使用getAttribute()和setAttribute()来读和写非标准属性的值,但为此付出的代价是文档将不再是合法有效的HTML。
HTML5提供了一个解决方案。在HTML5种,任意以“data-”为前缀的小写的属性名字都是合法的。这些“数据集属性”将不会对其元素的表现产生影响,他们定义了一种标准的,附加额外数据的方法,并不是在文档合法性上做出让步。
HTML5还在Element对象上定义了dataset属性。该属性指代一个对象,它的各个属性对应于去掉前缀的data-属性。因此dataset.x应该保存data-x属性的值。带连字符的属性对应于驼峰命名法属性名:data-jquery-test属性就变成dataset.jqueryTest属性。

作为Attr节点的属性

还有一种使用Element的属性的方法。Node类型定义了attributes属性。针对非Element对象的任何节点,该属性为null。对于Element对象,attributes属性是只读的类数组对象,它代表元素的所有属性。类似NodeLists,attributes对象也是实时的。它可以用数字索引访问,这意味着可以枚举元素的所有属性,并且,它也可以用属性名索引。
document.body.attributes[0] //元素的第一个属性
document.body.attributes.bgcolor //元素的bgcolor属性
document.body.attributes[“ONLOAD”] //元素的onload属性
当索引attributes对象时得到的值是Attri对象。Attr对象一类特殊的Node,但从来不会 像Node一样去用。Attri的name和value属性返回该属性的名字和值。

元素的内容

作为HTMl的元素内容

读取Element的innerHTML属性作为字符串标记返回那个元素的内容。在元素上设置该属性调用了Web浏览器的解析器,用新字符串内容的解析展现形式替换元素当前内容。
Web浏览器很擅长解析HTML,通常设置innerHTML效率非常高,甚至在指定的值需要解析时效率也相当不错。但注意,对innerHTML属性用“+=”操作符重复追加一小段文本通常效率低下,因为它既要序列化又要解析。

作为纯文本的元素内容

有时需要查询纯文本形式的元素内容,或者在文档中插入纯文本(不必转译HTML标记中使用的尖括号和&符号)。标准的方法是Node的textContent属性来实现:
var para = document.getElementsByTagName(“p”)[0]; //文档中的第一个

var text = para.textContent; //文本是“This is a simple document.”
para.textContext = “Hello World!”; //修改段落内容
textContent属性在除了IE的所有当前浏览器中都支持。在IE中,可以用Element的innerText代替,出了Firefox所有浏览器都支持。
textConten和innerText属性非常相似,通常可以互相替换使用。

创建、插入和删除节点

创建节点

创建新的Element节点可以使用Document对象的creatElement()方法。给方法传递元素的标签名:对HTML文档来说该名字不区分大小写,对XML文档则区分大小写。
var s = document.createElement(“script”);
Text节点用类似的方法创建:
var newnode = document.createTextNode(“text node content”);
另一种创建新文档节点的方法是复制已存在的节点。每个节点有一个cloneNode()方法来返回该节点的一个全新副本。给方法传递参数true也能够递归的复制所有的后代节点,或传递参数false只是执行一个浅复制。在除了IE的其他浏览器中,Document对象还定义了一个类似的方法叫importNode()。如果给他传递另一个文档的一个节点,它将返回一个适合本文档插入的节点的副本。传递true作为第二个参数,该方法将递归的导入所有的后代节点。

插入节点

一旦有了新节点,就可以用Node的方法appendChild()或insertBefore()将它插入到文档中。appendChild()是在需要插入的Element节点上调用的,它插入指定的节点使其成为那个节点的最后一个子节点。
insertBefore()就像appendChild()一样,除了它接受两个参数。第一个参数就是待插入的节点,第二个参数是已存在的节点,新节点将插入该节点的前面。该方法应该在新节点的父节点上调用,方法的第二个参数必须是该父节点的子节点。如果传递null作为第二个参数,insertBefore()的行为类似appendChild(),它将节点插入在最后。

如果调用appendChild()或insertBefore()将已存在文档中的一个节点再次插入,那个节点将自动从它当前的位置删除,并在新的位置重新插入:没有必要显示删除该节点。

删除和替换节点

removeChild()方法是从文档树种删除一个节点。但是请小心:该方法不是在待删除的节点上调用,而是在其父节点上调用。在文档中删除n节点,代码可以这样写:
n.parentNode.removeChild(n);
replaceChild()方法删除一个子节点并用一个新的节点取而代之。在父节点上调用该方法,第一个参数是新节点,第二个参数是需要代替的节点。如一个文本字符串来低缓节点n,代码可以这样写:
n.parentNode.replaceChild(document.createTextNode([” REDACTED “]),n);

使用DocumentFragment

DocumentFragment是一种特殊的Node,它作为其他节点的一个临时的容器。像这样创建一个DocumentFragment:
var frag = document.createDocumentFragment();
像Document节点一样,DocumentFragment是独立的,而不是任何其他文档的一部分。它的parentNode总是null。但类似Element,它可以有任意多的子节点,可以用appendChild(),insertBefore()等方法来操作她们。
DocumentFragment的特殊之处在于它使得一组节点被当作一个节点看待:如果给appendChild(),insertBefore()或replaceChild()传递一个DocumentFragment,其实是将该文档片段的所有子节点插入到文档中,而非片段本身。

文档和元素的几何形状和滚动

文档坐标和视口坐标

元素的位置是以像素来度量的,向右代表X坐标的增加,向下代表Y坐标的增加。但是,有两个不同的点作为坐标系的原点:元素的X和Y坐标可以相对于文档的左上交或者相对于其中显示文档的视口的左上角。
如果文档比视口要小,或者说它还未出现滚动,则文档的左上角就是视口的左上角,文档和视口坐标系统是同一个。但是,一般来说,要在两种坐标系之间互相转换,必须加上或减去滚动的偏移量。
文档坐标比视口坐标更加基础,并且在用户滚动时他们不会发生变化。为了在坐标系之间互相转换,需要判定浏览器窗口的滚动条的位置。Window对象的pageXOffset和pageYOffset属性在所有的浏览器中提供这些值,出来IE8及更早的版本。IE(和所有现代浏览器)也可以通过scrollLeft和scrollTop属性来获得滚动条的位置。

查询元素的几何尺寸

判定一个元素的尺寸和位置最简单的方法是调用它的getBoundingClientRect()方法。无需参数,返回一个有left、right、top和bottom属性的对象。left和top属性表示元素的左上角的X和Y坐标,right和bottom属性表示元素的右下角的X和Y坐标。

判定元素在某点

getBoundingClientRect()方法使我们能在视口中判定元素的位置。但有时我们想反过来,判定在视口中的指定位置上有什么元素。这可以用Document对象的elementFromPoint()方法来判定。传递X和Y左边(使用视口坐标而非文档坐标),该方法返回在指定位置的一个元素。

滚动

元素的位置是以像素来度量的,向右代表X坐标的增加,向下代表Y坐标的增加。有两个不同的点作为坐标系的原点:元素的X和Y坐标可以相对于文档的左上角或者相对于在其中显示文档的视口的左上角。
Window对象的scrollTop()方法,接受一个点的X和Y坐标(文档坐标),并作为滚动条的偏移量设置它们。
Window的scrollBy()方法和scroll()和scrollTo()类似,但是它的参数是相对的,并在当前滚动条的偏移量上增加。

关于元素尺寸、位置和溢出的更多信息
getBoundingClientRect()方法在所有当前的浏览器上都有定义,但如果需要支持老式浏览器,不能依靠此方法而必须使用更老的技术来判断元素的尺寸和位置。元素的尺寸比较简单:任何HTML元素的只读属性offseWidth和offsetHeight以CSS像素返回它的屏幕尺寸。返回的尺寸包含元素的边框和内边距,除去了外边距。

HTML表单

HTML的

元素和各种各样的表单输入元素在客户端编程中有着重要的地位,是第一代Web应用程序背后的运作机制,它根本就不需要JavaScript。用户的输入从表单元素来收集,表单将这些输入递交给服务器,服务器输入并生成一个新的HTML页面,显示在客户端。
即使当整个表单数据都是由客户端JavaScript来处理并不会提交到服务器时,HTML表单元素仍然是收集用户数据很好的方法。在服务端程序中,表单必须要有一个“提交”按钮,否则它就没有用处。

表单和元素的属性

在JavaScript产生之前,要用一个专用的“提交”按钮来提交表单,用一个专用的“重置”按钮来重置各表单元素的值。JavaScript的From对象支持两个方法:submit()和reset(),他们完成同样的目的。调用Form对象的submit()方法来提交表单,调用reset()方法来重置表单元素的值。
所有(多数)表单元素通常都有以下属性:
type:标识表单元素类型的只读的字符串。针对用<input>标签定义的表单元素而言,就是其type属性的值。其他表单元素定义type属性是为了轻松的标识它们,与<input>元素在类型检测时互相区别。
form:对包含元素的Form对象的只读引用,或者如果元素没有包含在一个元素中则其值为null。
name:只读的字符串,由HTML属性name制定。
value:可读/写的字符串,指定了表单元素包含或代表的值。它就是当提交表单时发送到Web服务器的字符串。

表单和元素的事件处理程序

每个Form元素都有一个onsubmit事件处理程序来侦测表单提交,还有一个onreset事件处理程序来侦测表单重置。表单提交前调用onsubmit程序,它通过返回false能够取消提交动作。onsubmit事件处理程序只能通过单击“提交”按钮来触发。直接调用表单的submit方法不触发onsubmit事件处理程序。
onreset事件处理程序在表单重置之前调用,通过返回false能够阻止表单元素被重置。如果使用,可能需要提醒用户来确认是否重置。与onsubmit事件处理程序类似,onreset只能通过单击“重置”按钮来触发,直接调用表单的reset()方法不触发onreset事件处理程序。

开关按钮

复选框和单选元素都是开关按钮,或称有两种视觉状态的按钮:选中或未选中。通过对其单击用户可以改变它的开关状态。单选元素为整组有相关性的元素而设计,组内所有的按钮的HTML属性的name的值都相同。按这种方式创建的单选按钮是互斥的:选中其一,之前选中的即变成未选中。复选框通常也整组使用并共享name属性,必须注意的是当利用作为表单属性的名字来选中这些元素时,它返回一个类数组对象而不是单个元素。

文本域

文本输入域在HTML表单和JavaScript程序中可能是最常用的元素。用户可以输入单行简短的文本字符串。value属性表示用户输入的文本。通过设置该属性可以显示的指定应该在输入域中显示的文本。
Textarea元素类似文本输入域元素,不同的是它允许用户输入多行文本。
<input type=”password”>元素在用户输入时显示为星号,它修改了输入的文本。注意,密码输入元素只能防止眼睛窥视,但在提交表单时输入未经任何加密(除非通过HTTPS连接提交),当在网络上传输时它可能被看见。
<input type=”file”>元素将用户输入待上传到Web服务器的文件的名称。它由一个文本域和一个单击打开文件选择对话框的按钮所组成。该文件选取元素拥有onchange事件处理程序,就像普通的输入域一样。但不同的是它的value属性是只读的。

选择框和选项元素

Select元素表示用户可以走出选择的一组选项(用Option元素表示)。浏览器通常将其渲染为下拉菜单的形式,当当制定其size属性大于1时,它将显示列表中的选项。Select元素能以两种不同的方式运作,这取决于它的type属性是如何设置的。如果元素有multiple属性,也就是Select对象的type属性为“select-multiple”,那就允许用户选取多个选项。否则,如果没有多选属性,那只能选取单个选项,它的type属性为“select-one”。

其他文档特性

Document的属性

cookie:允许JavaScript程序读、写HTTP cookie的特殊的属性。
domain:该属性允许当Web页面之间交互时,相同域名下互相信任的Web服务器之间写作放宽同源策略安全限制。
lastModified:包含文档修改时间的字符串。
location:与Window对象的location属性引用同意Location对象。
referrer:如果有,它表示浏览器导航到当前连接的上一个文档。该属性值和HTTP的Referer头信息的内容相同,只是拼写上有两个r。
title:文档和标签之间的内容。URL:文档的URL,只读字符串而不是Location对象。该属性值与location.href的初始值相同,只是不包含Location对象的动态变化。