DOM(文档对象模型)是针对 HTML 和 XML 文档的一个 API(应用程序编程接口)。DOM描绘了一个层次化的节点树,允许开发人员添加、移除和修改页面的某一部分。DOM 脱胎于Netscape 及微软公司创始的 DHTML(动态 HTML),但现在它已经成为表现和操作页面标记的真正的跨平台、语言中立的方式。
10.1 节点层次
DOM 可以将任何 HTML 或 XML 文档描绘成一个由多层节点构成的结构。节点分为几种不同的类 型,每种类型分别表示文档中不同的信息及(或)标记。每个节点都拥有各自的特点、数据和方法,另外也与其他节点存在某种关系。节点之间的关系构成了层次,而所有页面标记则表现为一个以特定节点为根节点的树形结构。
文档元素即<html>元素
文档元素是文档的最外层元素,文档中的其他所有元素都包含在文档元素中。每个文 档只能有一个文档元素。在 HTML 页面中,文档元素始终都是<html>元素。
文档类型
HTML 元素通过元素节点表示,特性(attribute)通过特性节点表示,文档类型通过文档类型节点表示,而注释则通过注释节点表示。总共有 12 种节点类型,这些类型都继承自一个基类型。
10.1.1 Node类型
DOM1 级定义了一个 Node 接口,该接口将由 DOM 中的所有节点类型实现。JavaScript 中的所有节点类型都继承自 Node 类型,因此所有节点类型都共享着相同的基本属性和方法。IE不能访问该类型
每个节点都有一个 nodeType 属性,用于表明节点的类型。节点类型由在 Node 类型中定义的下列12 个数值常量来表示,任何节点类型必居其一:
- 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 == Node.ELEMENT_NODE){ //在 IE 中无效
alert("Node is an element.");
}
上述代码通过比较nodeType属性的值 是否于 Node.ELEMENT_NODE 常量相等,来判断someNode是否为一个元素。因为IE没有公开Node类型的构造函数,所以IE中会导致错误。 通用的判断节点类型的方法是将 nodeType 属性与数字值进行比较
if (someNode.nodeType == 1){ //适用于所有浏览器
alert("Node is an element.");
}
1. nodeName 和 nodeValue 属性
如果是元素节点,nodeName 返回元素标签名,nodeValue返回null;
如果是文本节点,nodeName 返回 "#text", nodeValue返回文本的内容。
2. 节点关系
childNodes
每个节点都有一个 childNodes 属性,其中保存着一个 NodeList 对象。NodeList 是一种类数组对象,用于保存一组有序的节点,可以通过位置来访问这些节点。NodeList 是动态的。以下是访问保存在NodeList中的节点 方式:
var firstChild = someNode.childNodes[0];
var secondChild = someNode.childNodes.item(1);
var count = someNode.childNodes.length;
parentNode
该属性指向文档树中的父节点。
previousSibling
该属性指向当前节点的上一个兄弟节点,如果当前节点是第一个节点,则为null。
nextSibling
该属性指向当前节点的下一个兄弟节点,如果当前节点是最后一个节点,则为null。
firstChild
该属性指向当前节点的第一个子节点,相当于someNode.childNodes[0] ,
lastChild
该属性指向当前节点的最后一个子节点,someNode.childNodes[someNode.childNodes.length-1]。
hasChildNodes()
这个方法在节点包含一或多个子节点的情况下返回 true;
ownerDocument
该属性指向表示整个文档的文档节点。。通过这个属性,我们可以不必在节点层次中通过层层回溯到达顶端,而是可以直接访问文档节点。
节点关系图
3. 操作节点
appendChild()
用于向 childNodes 列表的末尾添加一个节点。返回新增的节点。
如果传入的是父节点的第一个子节点,那么该节点会成为最后一个子节点。
//someNode 有多个子节点
var returnedNode = someNode.appendChild(someNode.firstChild);
alert(returnedNode == someNode.firstChild); //false
alert(returnedNode == someNode.lastChild); //true
insertBefore()
这个方法接受两个参数:要插入的节点和作为参照的节点。该方法会把要插入的节点插入到 参照的节点前面;如果参照节点为null,则把要插入的节点插入到末尾。
replaceChild()
方法接受的两个参数是:要插入的节点和要替换的节点。要替换的节点将由这个 方法返回并从文档树中被移除,同时由要插入的节点占据其位置。
removeChild()
这个方法接受一个参数,即要移除的节点。被移除的节点将成为方法的返回值
4. 其他方法
cloneNode()
方法接受一个布尔值参数,表示是否执行深复制。true表示深复制,即复制节点及其整个子节点树;false表示浅复制。该方法不会复制DOM节点中Javascript属性,例如事件处理程序。
10.1.2 Document类型 和 document对象
JavaScript 通过 Document 类型表示文档。在浏览器中,document 对象是 HTMLDocument(继承自 Document 类型)的一个实例,表示整个 HTML 页面。document 对象是 window 对象的一个属性,因此可以将其作为全局对象来访问。
文档的子节点
document.documentElement
该属性始终指向HTML 页面中的<html>元素,相当于document.childNodes\[0]和document.firstChild。
document.body
该属性直接指向直接指向<body>元素。通过该属性获取body元素是最佳方式。
2. 文档信息
title
该属性包含着\<title>元素中的文本——显示在浏览器窗口的标题栏或标签页上。
URL
该属性包含页面完整的 URL(即地址栏中显示的 URL)
domain
该属性中只包含页面的域名
referrer
属性中可能会包含空字符串
3. 查找元素
- getElementById()
- getElementsByTagName()
- getElementsByName()
4.特殊集合
- document.anchors,包含文档中所有带 name 特性的<a>元素;
- document.forms,包含文档中所有的<form>元素,与 document.getElementsByTagName("form")
- document.images,包含文档中所有的<img>元素,与 document.getElementsByTagName("img")得到的结果相同;
- document.links,包含文档中所有带 href 特性的<a>元素。
5.文档写入
document.write()
接收一个字符串,原样写入文档流。
document.writeln()
接受一个字符串,在字符串的末尾添加一个换行符(\n)
document.open()
打开网页的输出流
document.close()
关闭网页的输出流
10.1.3 Element类型
Element 节点具有以下特征:
- nodeType 的值为 1;
- nodeName 的值为元素的标签名;
- parentNode 可能是 Document 或 Element;
- 其子节点可能是 Element、Text、Comment(注释节点)、ProcessingInstruction(处理指令节点)、
CDATASection或 EntityReference(实体字符)
HTML元素
HTMLElement 类型直接继承自Element 并添加了一些属性
- id,元素在文档中的唯一标识符。
- title,有关元素的附加说明信息,一般通过工具提示条显示出来
- lang,元素内容的语言代码,很少使用。
- dir,语言的方向,可取值为 "ltr" 或者 "rtl"
- className, 与元素的class 特性对应
操作元素特性
- getAttribute()
- setAttribute()
- removeAttribute()
注意:当操作html元素上的class属性时,传 class 而 非 className。这三种方法可以操作HTMLElement 类型属性和自定义属性。
创建元素
使用document.createElement创建元素。
var div = document.createElement("div");
div.id = "myNewDiv";
div.className = "box";
document.body.appendChild(div);
10.1.4 Text类型
Text 节点具有以下特征
- nodeType 的值为 3;
- nodeName 的值为"#text";
- nodeValue 的值为节点所包含的文本;
- parentNode 是一个 Element;
- 没有子节点
创建文本节点
document.createTextNode()
10.1.5 Comment类型
注释在 DOM 中是通过 Comment 类型来表示的。Comment 节点具有下列特征:
- nodeType 的值为 8;
- nodeName 的值为"#comment";
- nodeValue 的值是注释的内容;
- parentNode 可能是 Document 或 Element;
- 不支持(没有)子节点。
创建注释节点
document.createComment()
10.1.8 DocumentFragment类型
DOM 规定文档片段(document fragment)是一种“轻量级”的文档,可以包含和控制节点,但不会像完整的文档那样占用额外的资源。。DocumentFragment 节点具有下列特征:
- nodeType 的值为 11;
- nodeName 的值为"#document-fragment";
- nodeValue 的值为 null;
- parentNode 的值为 null;
- 子节点可以是 Element、ProcessingInstruction、Comment、Text、CDATASection 或 EntityReference。
创建DocumentFragment类型
document.createDocumentFragment()
其他的类型节点
CDATASection类型nodeType 的值为 4,只针对基于 XML 的文档,表示的是 CDATA 区域。
DocumentType类型的nodeType为10,包含着与文档的 doctype 有关的所有信息。
Attr类型的nodeType 的值为 2,表示存在于元素的 特性。特性就是存在于元素的 attributes 属性中的节点,但不是是 DOM 文档树的一部分
10.2 DOM 操作技术
10.2.1 动态创建script标签
使用<script>元素可以向页面中插入 JavaScript 代码,一种方式是通过其 src 特性包含外部文件,另一种方式就是用这个元素本身来包含代码。
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "client.js";
document.body.appendChild(script);
10.2.2 动态样式
所谓动态样式是指在页面刚加载时不存在的样式;动态样式是在页面加载完成后动态添加到页面中的。
动态创建link标签
var link = document.createElement("link");
link.rel = "stylesheet";
link.type = "text/css";
link.href = "style.css";
var head = document.getElementsByTagName("head")[0];
head.appendChild(link);
动态创建style标签
var style = document.createElement("style");
style.type = "text/css";
style.appendChild(document.createTextNode("body{background-color:red}"));
var head = document.getElementsByTagName("head")[0];
head.appendChild(style);
10.2.4 使用NodeList
所有 NodeList 对象都是在访问 DOM 文档时实时运行的查询。
应该尽量减少访问 NodeList 的次数。
可以考虑将从 NodeList 中取得的值缓存起来