DOM(文档对象模型)是针对HTML和XML文档的一个API。DOM描绘了一个层次化的节点树。允许开发人员添加、移除、修改页面的某一部分。
文档节点是每个文档的根节点,文档元素是文档的最外层元素,文档中其他说有的元素都包含在文档元素中,每个文档只能有一个文档元素,在HTML 中,文档元素始终是<html> 元素,在XML 中没有预定义的元素,因此任何元素都可能成为文档元素。
每一段标记都可以通过树中的一个节点来表示:HTML 元素通过元素节点表示,特性(attribute)通过特性节点表示,文档类型通过文档类型节点表示,而注释则通过注释节点表示,总共有12 种节点类型。
1.Node类型
DOM1 级定义了一个Node 接口,该接口将由DOM中所有节点类型实现。这个Node在JavaScript中是作为Node 类型实现的;JavaScript 中所有节点都继承自Node 类型,因此所有节点类型都共享相同的基本属性和方法。
属性
每个节点都有一个nodeType 属性,用于表明节点的类型。节点类型由在Node类型中定义的下列 12 个数值常量来表示,任何节点类型必居其一。
可以用节点的nodeType属性和上面的常量比较,如果相等,则说明节点是 该类型的元素。由于IE没有公开Node类型的构造函数,所以为了确保跨浏览器兼容,最好还是将nodeType属性与数字值进行比较。
if(someNode.nodeType == 1){ //Node.ELEMENT_NODE alert("Node is an element"); }
可以使用nodeName 和 nodeValue 者两个属性来了解节点的具体信息,对于元素节点,nodeName中保存的始终都是元素的表签名,而nodeValue 则始终为null。
每一个节点都保存者一个childNodes 属性,其中保存着一个NodeList对象。NodeList是一种类似于数组的对象,用于保存一组有序的节点。NodeList 对象的独特之处在于,它实际上是基于DOM结构动态执行查询的结果,因此DOM结构的变化能够自动反应在NodeList 对象中。
可以使用方括号或者item方法来访问NodeList中的对象。
var firstChild = someNode.childNodes[0]; var secondChild = someNode.childNodes.item(1); var count = someNode.childNodes.length;
可以使用Array.prototype.slice()方法将NodeList转换成普通的ArrayList对象。
var arrayOfNodes = Array.prototype.slice.call(someNode.childNodes, 0);
每个节点还有 prentNode、previousSibling、nextSibling、firstChild、lastChild等属性。顾名思义,不再一一介绍。
方法
节点的关系指针都是只读的,所以DOM提供了一些操作节点的方法。其中最常用的是appendChild(),用于向childNodes 列表的末尾添加一个节点。返回新增的节点。
使用insertBefore()方法可以把节点方法childNodes 列表中某个特定的位置上。接收两个参数:要插入的节点和作为参照的节点。插入节点后,被插入的节点会变成参照节点的前一个兄弟节点(previousSibling),同时被方法返回。如果参照节点是null, 则insertBefore() 与 appendChild() 执行相同的操作。
replaceChild()方法接收两个参数:要插入的节点和要替换的节点。要替换的节点将由这个方法返回并从文档树中被移除,同时由要插入的节点占据其位置。
removeChild()方法接收一个参数,即要移除的节点。被移除的节点将成为方法的返回值。
cloneNode() 用于创建调用这个方法的节点的一个完全相同的副本。该方法接收一个布尔值参数,表示是否执行深复制。
2.Document类型
JavaScript 通过Document 类型表示文档,在浏览器中,document 对象是HTMLDocument的一个实例,表示整个HTML页面。而且document对象是window对象的一个属性,因此可以作为全局对象来访问。
document 的 nodeType 为9, nodeName 为“#document”,nodeValue 为null parentNode 为null,ownerDocument为null。
Document 节点的子节点可以是DocumentType、Element、ProcessingInstruction 或 Comment,但还是有两个内置的访问其子节点的快捷方式。
第一个就是documentElement 属性,该属性始终指向 HTML 页面中的<html> 元素。另一个就是body 属性,直接指向<body> 元素。
document 对象有一些标准的Document 对象所没有的属性。这些属性提供了document 对象所表现的页面的一些信息。
第一个属性是 title,包含者<title> 元素中的文本----显示在浏览器窗口的标题栏或标签页上。通过这个属性可以取得当前页面的标题,也可以修改当前页面的标题并反应在浏览器的标题栏中。
URL属性中包含页面完整的URL,domain 属性中包含页面的域名,而referrer 属性中则保存着联街道当前页面的哪个页面的URL。在没有来源页面的情况下,referrer 属性中可能会包含空字符串。所有这些信息都存在于请求的HTTP 头部,只不过是通过这些属性让我们能够在JavaScript中访问他们而已。
document提供了两个方法用于查找某个或某组元素的引用:getElementById() 和 getElementsByTagName()。
getElementsByTagName() 函数返回的是包含0或多个元素的 NodeList。在HTML中,这个方法会返回一个HTMLCollection 对象,作为一个动态集合,该对象与NodeList 非常类似。
getElementsByName() 方法是HTMLDocument 特有的方法,返回带有给定name 特性的所有元素。
document对象还有一些特殊的集合,这些集合都是HTMLCollection对象,为访问文档常用部分提供了快捷方式。
3.Element类型
要访问元素的标签名,可以使用nodeName属性,也可以使用tagName 属性;这两个属性会返回相同的值。
所有的HTML元素都由HTMLElement 类型表示,不是直接通过这个类型也是通过它的子类型来表示。HTMLElement 类型直接继承自Element 并添加了一些属性。添加的这些属性分别对应于每个HTML都存在的下列标准特性:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>study</title> </head> <body> <div id="myDiv" class="bd" title="Body text" lang="en" dir="rtl">good morning</div> <script type="text/javascript"> var div = document.getElementById("myDiv"); alert("id=" + div.id + ", class=" + div.className + ", title=" + div.title + ", lang=" + div.title + ", dir=" + div.dir); //id=myDiv, class=bd, title=Body text, lang=Body text, dir=rtl </script> </body> </html>
getAttribute()方法也可以取得属性内容,也可以取得自定义的特性。参数传递属性名称,不去分大小写。
在通过JavaScript 以编程方式操作DOM 时,开发人员经常不使用getAttribute(),而是只使用对象的属性。只有在取得自定义特性值的情况下,才会使用getAttribute() 方法。
setAttribute() 方法可以为对象设置属性,也可以操作自定义特性,通过这个方法设置的特性名会被统一转换成小写形式。
removeAttribute() 方法用于彻底删除元素的特性。调用这个方法不仅会清除特性的值,而且也会从元素中完全删除特性。
Element 类型是使用attributes 属性的唯一一个DOM 节点类型。attributes 属性中包含一个NamedNodeMap,是一个动态集合。元素的每一个特性都是一个Attr节点表示,每个节点都保存在NamedNodeMap对象中。NamedNodeMap对象拥有下列方法:
attributes属性中包含一系列节点,每个节点的nodeName 就是特性的名称,而节点的 nodeValue 就是特性的值。要取得元素的id特性,可以使用以下代码。
var id = element.attributes.getNamedItem("id").nodeValue; var id = element.attributes["id"].nodeValue; element.attributes["id"].nodeValue = "newId";
一般来说,因为attributes 的方法不够方便,因此开发人员更多的会使用 getAttribute()、setAttributes()、removeAttributes()方法。
创建元素,使用document.creatElement()可以创建新元素,这个方法只接收一个参数,即要创建元素的标签名,
var div = document.createElement("div"); div.id = "myNewDiv"; div.className = "box";
4.Text类型
可以通过nodeValue 属性或者 data 属性来访问Text 节点中包含的文本,这两个属性中包含的值相同。对nodeValue的修改也会通过data反映出来,反之亦然。
可以使用下列方法来操作节点中的文本。
文本节点还有一个length 属性,保存着节点中字符的数目。
创建文本节点,可以使用 document.createTextNode()创建新文本节点,这个方法接受一个参数----要插入的文本。
操作表格
<table> 元素是 HTML中最复杂的结构之一,要想创建表格,一般都必须设计表示表格行、单元格、表头等方面的标签。由于涉及的标签多,因此使用核心的DOM方法创建和修改表格往往都免不了要编写大量的代码。为了方便构建表格,HTML DOM 还为<table>、<tbody>和<tr>元素添加了一些属性和方法。
为<table>元素添加的属性和方法:
为<tbody> 元素添加的属性和方法:
为<tr>元素添加的属性和方法:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>study</title> </head> <body> <script type="text/javascript"> var table = document.createElement("table"); table.border = 1; table.width = "100%"; //create tbody var tbody = document.createElement("tbody"); table.appendChild(tbody); //first row tbody.insertRow(0); tbody.rows[0].insertCell(0); tbody.rows[0].cells[0].appendChild(document.createTextNode("Cell 1, 1")); tbody.rows[0].insertCell(1); tbody.rows[0].cells[1].appendChild(document.createTextNode("Cell 1, 2")); //second row tbody.insertRow(1); tbody.rows[1].insertCell(0); tbody.rows[1].cells[0].appendChild(document.createTextNode("Cell 2, 1")); tbody.rows[1].insertCell(1); tbody.rows[1].cells[1].appendChild(document.createTextNode("Cell 2, 2")); document.body.appendChild(table); </script> </body> </html>
NodeList
NodeList、NamedNodeMap 和 HTMLCollection 三个集合都是动态的集合,每当文档结构发生变化是,他们都会更新。因此他们始终都会保存着最新、最准确的信息。从本质上说,所有NodeList对象都是在访问DOM文档时实时运行查询。
var divs = document.getElementsByTegName("div"), i, div; for(i = 0; i < divs.length; i++){ div = document.createElement("div"); document.body.appendChild(div); }
由于divs是动态集合,所以上面代码会导致无限循环,解决方法是把divs.length保存到另一个变量中进行缓存。
一般来说,应该尽量减少访问NodeList的次数。
DOM是语言中立的 API,用于访问HTML 和XML 文档。DOM1级将HTML和XML 文档形象地看做一个层次化的节点树,可以使用JavaScript来操作这个节点树,进而改变底层文档的外观和结构。