Client-side Javascript的主要目的是脚本化web page内容, 把静态的HTML转换成交互式的web应用程序. Scripting Document的主要内容:html
DOM的基本架构;node
怎样从Document query和select元素(Element);web
怎样遍历(Traverse)Document, 怎么查找任何一个document元素的祖先(ancestors),兄弟(siblings),子孙(descendant);数组
怎样query和set document元素的属性;架构
怎样query,set和modify document的内容;ide
怎样经过creating,inserting和deleting节点(node)来改变document的结构;oop
HTML form怎样工做;spa
DOM概要orm
DOM是表示和操做HTML和XML的基本API, HTML和XML文档的嵌套元素用DOM表示成对像树,HTML文档(document)包含表示HTML标签(tag)和元素(element)的节点(node)和表示文本字符串的节点(node), HTML document也包含表示声明(comments)的节点.server
<html> <head> <title>Sample Document</title> </head> <body> <h1>An HTML Document</h1> <p>This is a <i>simple</i> document. </html>
从上图树的根是Document Node,表示整个文档; 表示HTML元素的节点是HTML Node; 表示文本的是Text Node, Document, Element和Text是Node的子类.
从上面的类层次图,须要注意的是Document和Element,HTMLDocument和HTMLElement之间是有区别的, Document要么表示HTML文档, 要么表示XML文档, 而Element则表示Document的元素. HTMLDocument和HTMLElement都是Document和Element的子类.
2. 查找Document元素
Client-side Javascript程序从某种程度来讲就是操做一个或多个元素, 当程序启动后,使用全局变量document引用文档对象. 为了操做文档元素, 须要查找要操做的元素, DOM定义以下方法来查找元素:
使用指定的属性id;
使用指定的属性name;
使用指定的标签name;
使用指定的CSS class;
匹配指定的CSS选择器;
2.1 经过属性ID查找元素
任何HTML元素都有一个在整个文档惟一的id属性, 所以能够经过使用文档对象的getElementById()来查找元素. getElementById()方法只能查找一个元素,若是须要查找多个元素,能够使用以下的方法:
function getElements(/*ids...*/) { var elements = {}; for(var i = 0; i < arguments.length; i++) { var id = arguments[i]; var elt = document.getElementById(id); if (elt == null) throw new Error("No element with id: " + id); elements[id] = elt; } return elements; }
2.2 经过属性Name查找元素
HTML name属性最初是为了给form元素设定name, 并且name属性只有在form数据在提交给server时才被使用, 须要注意的是name属性值是不惟一的,好比在form中的radio按钮和checkboxes. 还有name属性只有在少部分元素上是合法的, 好比form,<iframe>,<img>. 若根据name属性查找元素, 能够使用文档对象的getElementsByName()方法, 如:
var radiobuttons = document.getElementsByName("favorite_color");
getElementsByName()经过HTMLDocument类定义,而不是Document类, 因此只能在HTML文档上使用,不能在XML文档上使用, 该方法返回一个read-only的元素对象数组.
2.3 经过属性Type查找元素
经过文档对象的getElementsByType()方法能够查找指定Type的全部HTML和XML元素, 该方法返回一个read-only的元素对象数组. 如:
var spans = document.getElementsByTagName("span");
getElememtsByTagName()返回的元素顺序是元素在文档中顺序, 好比在文档中查找第一个<p>元素能够用:
var firstpara = document.getElementsByTagName("p")[0];
HTML tag是大小写不明感的, 当用getElememtsByTagName()时,会忽略大小进行name的比较. 也能够在getElememtsByTagName()中使用通配符*查找全部元素. 除了Document类定义了getElememtsByTagName(), Element类也定义了getElememtsByTagName(),其使用跟Document的同样,只是getElememtsByTagName()只返回调用它的元素的子孙. 如:
var firstpara = document.getElementsByTagName("p")[0]; var firstParaSpans = firstpara.getElementsByTagName("span");
2.4 经过CSS class查找元素
HTML的class属性是以空格分开的一个或多个标识符, 同getElememtsByTagName()同样,getElementsByClass()能够被HTML document和HTML element调用, 返回匹配的class的read-only的全部子孙. 需注意的是getElementsByClass()方法以空格分隔class标识符, 而不是逗号.如:
var warnings = document.getElementsByClassName("warning"); var log = document.getElementById("log"); var fatal = log.getElementsByClassName("fatal error");
2.5 经过CSS选择器查找元素
CSS stylesheets使用Selector描述文档中的元素和元素集.
元素能够经过ID, tag name或者class来描述, 如: #nav, div, .warning
元素能够经过属性值查找, 如: p[lang="fr"] *[name="x"]
基本选择器能够被合并, 如: span.fatal.error span[lang="fr"].warning
选择器也能够指定文档结构, 如: #log span #log>span body>h1:first-child
能够合并选择器来查找多个元素和元素集, 如: div, #log
W3C定义了标准的API querySelectorAll()来查找指定选择器的元素, 该方法返回元素不像上述查找的元素,是not live的, 也就是返回的Nodelist保存该方法调用时匹配的元素, 当文档结构发生变化时不会更新. 若是该方法没有查到匹配的元素, 返回空的Nodelist, 若是发生错误, 抛出异常错误. 除了querySelectorAll(), document也定义了querySelector(), 使用方法同querySelectorAll(),但该方法只返回第一个匹配的元素, 若是没有匹配的, 则返回null. 这两个方法也定义在Element类上, 但只返回调用该方法元素的子孙.
3. 文档结构和遍历
3.1 做为节点树的文档
parentNode:
当前节点的父节点,Document节点的父节点是null, 由于它没有父节点.
childNodes:
一个read-only的类数组对象.
firstChild, lastChild:
一个节点的第一孩子节点和最后孩子节点, null表示没有孩子.
nextSibling, previousSibling:
一个节点的下一个和前一个兄弟节点, 两个节点拥有共同的父节点.
nodeType:
节点的类型, Document节点的值9, Element节点的值是1, 文本节点的值是3, 声明节点的值是8, Document Faragment是11.
nodeValue:
文本和声明节点的文本内容.
nodeName:
元素的tag名字,转换成大写.
3.2 做为元素树的文档
Element对象的属性children只返回元素对象.
Text和Comment节点没有孩子, 这意味着Node.parentNode不会返回Text和Comment节点.
基于元素的文档遍历API是Element属性, 其等价于Node对象的child和sibling属性.
firstElementChild, lastElementChild
nextElementSibling, previousElementSibling
clildElementCount
function parent(e, n) { if (n === undefined) n = 1; while(n-- && e) e = e.parentNode; if (!e || e.nodeType !== 1) return null; return e; } function sibling(e,n) { while(e && n !== 0) { if (n > 0) { if (e.nextElementSibling) e = e.nextElementSibling; else { for(e=e.nextSibling; e && e.nodeType !== 1; e=e.nextSibling) /* empty loop */ ; } n--; } else { if (e.previousElementSibing) e = e.previousElementSibling; else { for(e=e.previousSibling; e&&e.nodeType!==1; e=e.previousSibling) /* empty loop */ ; } n++; } } return e; } function child(e, n) { if (e.children) { if (n < 0) n += e.children.length; if (n < 0) return null; return e.children[n]; } if (n >= 0) { if (e.firstElementChild) e = e.firstElementChild; else { for(e = e.firstChild; e && e.nodeType !== 1; e = e.nextSibling) /* empty */; } return sibling(e, n); } else { if (e.lastElementChild) e = e.lastElementChild; else { for(e = e.lastChild; e && e.nodeType !== 1; e=e.previousSibling) /* empty */; } return sibling(e, n+1); } }