DOM(文档对象模型)是针对HTML和XML文档的一个API。
10.1 节点层次
节点分为几种不同的类型,每种类型分别表示文档中不同的信息及(或)标记。每个节点拥有各自的特点、数据和方法,另外也与其他节点存在某种关系。
10.1.1 Node类型
JavaScript中的所有节点类型都继承自Node类型,因此所有节点类型都共享着相同的基本属性和方法。
每个节点都有一个nodeType属性,用于表明节点的类型。
Node.ELEMENT_NODE(1);
Node.ATTRIBUTE_NODE(2);
Node.TEXT_NODE(3);
Node.CDATA_SECTION_NODE(4);
Node.ENTITY_REFERENCE_NODE(5);
Node.ENTITY_NODE(6);
Node.PROCESSING_INSTRUCTION_NODE(7);
Node.COMMENT_NODE(8);
Node.DOCUMENT_NODE(9);
Node.DOCUMENT_TYPE_NODE(10);
Node.DOCUMENT_FRAGMENT_NODE(11);
Node.NOTATION_NODE(12);
if(someNode.nodeType == 1){//兼容所有浏览器
}
2.节点关系
每个节点都有childNodes属性,其中保存着一个NodeList对象,可以通过位置来访问这些节点,也有length属性,但它并不是Array的实例。
someNode.childNodes[0];
someNode.childNodes.item(0);
someNode.childNodes.length;
每个节点都有一个parentNode属性,该属性指向文档树中的父节点。
每个节点的previousSibling和nextSibling属性,可以访问同一列表中的其他节点。列表中第一个节点的previousSibling属性值为null,最后一个节点的nextSibling属性值为null。
父节点与其第一个和最后一个子节点之间也存在特殊关系。父节点的firstChild和lastChild属性分别指向其childNodes列表中的第一个和最后一个节点,没有的话为null。
所有节点都有的最后一个属性是ownerDocument,该属性指向表示整个文档的文档节点。
3.操作节点
appendChild(),用于向childNodes列表的末尾添加一个节点。添加节点后,childNodes的新增节点、父节点及以前的最后一个子节点的关系指针都会相应地得到更新。返回新增的节点。
如果传入到appendChild()中的节点已经是文档的一部分了,那结果就是将该节点从原来的位置转移到新位置。即使可以将DOM树看成是由一系列指针连接起来的,但任何DOM节点也不能同时出现在文档中的多个位置上。
insertBefore(),接受两个参数:要插入的节点和作为参照的节点。
replaceChild(),接受两个参数:要插入的节点和要替换的节点。要替换的节点将由这个方法返回并从文档树中被移除,移除的节点仍然为文档所有,只不过在文档中已经没有了自己的位置。
removeChild(),移除的节点仍然为文档所有,只不过在文档中已经没有了自己的位置。
以上方法操作的都是某个节点的子节点,并不是所有类型的节点都有子节点,如果在不支持子节点的节点上调用了这些方法,将会导致错误发生。
4、其他方法
有两个方法是所有类型的节点都有的。第一个就是cloneNode(),用于创建调用这个方法的节点的一个完全相同的副本。接受一个布尔值参数,表示是否执行深复制。在参数为true的情况下,执行深复制,也就是复制节点及其整个子节点树;在参数为false的情况下,执行浅复制,即只复制节点本身。复制后返回的节点副本属于文档所有,但并没有为它指定父节点。
normalize(),作用就是处理文档树中的文本节点。在该节点的后代节点中查找,如果找到了空文本节点,则删除它;如果找到相邻的文本节点,则将它们合并为一个文本节点。
10.1.2 Document类型
JavaScript通过Document类型表示文档。在浏览器中,document对象是HTMLDocument(继承自Document类型)的一个实例,表示整个HTML页面。document对象是window对象的一个属性,因此可以将其作为全局对象来访问。
1、文档的子节点
var html = document.documentElement;//取得对<html>的引用
var body = document.body;//取得对<body>的引用
var doctype = document.doctype;//取得对<!DOCTYPE>的引用
2、文档信息
var originalTitle = document.title;
document.title = "New page title";
var url = document.URL;
var domain = document.domain;
var referrer = document.referrer;
3、查找元素
getElementById()
getElementsByTagName()
getElementsByName()
4、特殊集合
document.anchors //所有带name特性的<a>元素
document.applets
document.forms
document.images
document.links
5、DOM一致性检测
//检测浏览器实现DOM的哪些部分,最好加上能力检测
document.implementation.hasFeature("XML","1.0");
6、文档写入
略
10.1.3 Element类型
1、HTML元素
div.tagName
div.nodeName
2、取得特性
div.getAttribute("class");
div.getAttribute("my_special_attribute");//根据HTML5规范,自定义特性应该加上data-前缀以便验证
div.my_special_attribute //undefined
3、设置特性
div.setAttribute("id","someOtherId");
div.id="someOtherId";
4、attributes属性
var id = element.attributes.getNamedItem("id").nodeValue;
var id = element.attributes["id"].nodeValue;
5、创建元素
document.createElement("div");
此时新元素尚未被添加到文档树中,一旦将元素添加到文档树中,浏览器就会立即呈现该元素。此后,对这个元素所作的任何修改都会实时反映在浏览器中。
6、元素的子节点
不同浏览器在看待这些节点方面存在显著的不同,执行某项操作以前,通常都要先检查一下nodeType属性。
10.1.4 Text类型
文本节点
1、创建文本节点
document.createTextNode();
2、规范化文本节点
如果在一个包含两个或多个文本节点的父元素上调用normalize()方法,则会将所有文本节点合并成一个节点
3、分割文本节点
10.1.5 Comment类型
略
10.1.6 CDATASection类型
略
10.1.7 DocumentType类型
略
10.1.8 DocumentFragment类型
略
10.1.9 Attr类型
Attr对象有3个属性:name、value和specified(是一个布尔值,用以区别特性是在代码中指定的,还是默认的)。
var attr = document.createAttribute("align");
attr.value = "left";
element.setAttributeNode(attr);
alert(element.attributes["align"].value);//"left"
alert(element.getAttributeNode("align").value);//"left"
alert(element.getAttribute("align"));//"left"
10.2 DOM操作技术
10.2.1 动态脚本
利用DOM创建Script元素,还有兼容IE的方式
10.2.2 动态样式
利用DOM创建Link元素,还有兼容IE的方式
10.2.3 操作表格
略
10.2.4 使用NodeList
理解NodeList及其“近亲”NamedNodeMap和HTMLCollection,是从整体上透彻理解DOM的关键所在。这三个集合都是“动态的”,从本质上说,所有NodeList对象都是在访问DOM文档时实时运行的查询。
//无限循环
var divs = document.getElementsByTagName("div");
i,
len,
div;
for(i=0;i<divs.length;i++){
div = document.createElement("div");
document.body.appendChild(div);
}
//改为这样的
for(i=0,len=divs.length;i<len;i++){
div = document.createElement("div");
document.body.appendChild(div);
}
一般来说,应该尽量减少访问NodeList的次数。因为每次访问NodeList,都会运行一次基于文档的查询。所以,可以考虑将从NodeList中取得的值缓存起来。