DOM
DOM(文档对象模型)是针对HTML和XML文档 的一个API(应用程序编程接口)。
节点层次
DOM可以将任何HTML或XML文档描绘成一个由多层节点构成的结构。
每个文档只能有一个文档元素,在HTML页面中,文档元素始终都是<html>
元素。
总共有12种节点类型:
Node类型
DOM1级定义了一个Node接口,该接口将由DOM中的所有节点类型实现。
JavaScript中的所有节点类型都继承自Node类型。
nodeType属性:用于表明节点的类型。
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)。
nodeName和nodeValue属性
了解节点的具体信息。
节点关系
每个节点都有一个childNodes属性,其中保存着一个NodeList对象。
NodeList对象:一种类数组的对象(不是数组,但是有length)。
通用的将NodeList对象转为数组的方法:
function converToArray(nodes) {
var array = null;
try {
array = Array.prototype.slice.call(nodes,0); //针对非IE浏览器
} catch (ex) {
array = new Array();
for (var i = 0,len = nodes.length; i < len; i++) {
array.push(nodes[i]);
}
}
return array;
}
每个节点都有一个parentNode属性,该属性指向文档树中的父节点。
对于同胞节点,通过使用列表中每个节点的previousSibling(上一个节点)和nextSibling(下一个节点)属性,可以访问同一列表中的其他节点。
父节点的firstChild和lastChild属性分别指向其childNodes列表中的第一个和最后一个节点。
hasChildNodes()方法:返回是否有字节点,Boolean类型。
每个节点都有的属性:ownerDocument:该属性指向表示整个文档的文档节点。
操作节点
appendChild()方法:用于向childNodes列表的末尾添加一个节点。
appendChild()返回新增的节点。
如果appendChild()中的节点已经是文档的一部分了,就将该节点从原来位置转移到新位置。
insertBefore()方法:接受两个参数:要插入的节点和作为参照的节点。
插入节点后,被插入的节点会变成参照节点的前一个同胞节点(previousSibling),同时被方法返回。
如果参照节点为null,则同appendChild()方法。
replaceChild()方法:接受两个参数:要插入的节点和要替换的节点。
removeChild()方法:接受一个参数,即是要移除的节点。
其他方法
两个所有类型的节点都有的方法:
cloneNode():用于创建调用这个方法的节点的一个完全相同的副本。
接受一个布尔值参数,表示是否执行深复制。
true:深复制,复制节点及其整个子节点树。
false:浅复制,只复制节点本身。
normalize():这个方法唯一的作用就是处理文档树中的文本节点。
删除文本,合并相邻文本节点。
Document类型
Document节点具有下列特征:
- nodeType的值为9;
- nodeName的值为"#document";
- nodeValue的值为null;
- parentNode的值为null;
- ownerDocument的值为null;
- 其子节点可能是一个DocumentType(最多一个)、Element(最多一个)、ProcessingInstruction或Comment。
文档的子节点
documentElement属性能更快捷、更直接地访问HTML中的<html>
元素。
获取body元素:document.body
获取<!DOCTYPE>
标签:document.doctype
文档信息
类似的还有:
document.title;
document.URL;(http获得的页面的URL)
document.domain(域名)
查找元素
两个方法:
- getElementById():通过id属性(怪癖:name属性也会被调用)
- getElementsByTagName():通过标签名。
HTMLDocument类型独有的方法:
getElementsByName():通过name属性。
特殊集合
都是HTMLCollection对象:
- document.anchors:所有带name特性发
<a>
元素。 - document.applets:文档中所有的
<applet>
元素。 - document.forms
- document.images
- document.links:文档中所有带href特性的
<a>
元素。
DOM一致性检测
document.implementation规定了一个方法:hasFeature()。
var hasXmlDom = document.implementation。hasFeature("XML","1.0");
文档写入
4个方法:
- write():接受一个字符串
- writeln():接受一个字符串
- open():打开网页的输出流
- close():关闭网页的输出流
Element类型
- nodeType的值为1
- nodeName的值为元素的标签名
- nodeValue的值为null
- parentNode可能是Document或Element;
- 其子节点可能是Element、Text、Comment、ProcessingInstruction、CDATASection或EntityReference。
在HTML中,标签名始终都以大写表示,而在XML(有时候也包括XHTML)中,标签名则始终会与源代码中的保持一致。
element.tagName.toLowerCase() == "div"
HTML元素
所有HTML元素都由HTMLElement类型表示。
- id,元素在文档中的唯一标识符。
- title,有关元素的附加说明信息,一般通过工具提示条显示出来。
- lang,元素内容的语言代码,很少使用。
- dir,语言的方向,ltr、rtl。
- className,与元素的class特性对应。
取得特性
每个元素都有一个或多个特性,这些特性的用途是给出相应元素或其内容的附加信息。
操作特性的DOM方法主要有三个:
- getAttribute():参数是特性名的字符串。
- setAttribute():同上
- removeAttribute():同上
两类特殊的特性:style和onclick。
设置特性
setAttribute(),替换或者创建。
这个方法设置的特性名会统一转换为小写形式。
attributes属性
Element类型是使用attributes属性的唯一一个DOM节点类型。
attributes属性中包含一个NameNodeMap。
NameNodeMap对象拥有的方法:
- getNameItem(name):返回nodeName属性等于name的节点。
- removeNamedItem(name)
- setNamedItem(name)
- item(pos)
为特性设置新值:
element.attributes["id"].nodeValue = "someOtherId";
创建元素
document.createElement()方法。
参数是要创建元素的标签名。HTML忽略大小写,XML区分大小写。
把新元素添加到文档树:
appendChild()、insertBefore()、replaceChild()。
注意点:
- 不能设置动态创建的
<iframe>
元素的name特性。 - 不能通过表单的reset()方法重设动态创建的
<input>
元素。 - 动态创建的type特性值为"reset"的
<button>
元素重设不了表单。 - 动态创建的一批name相同的单选框彼此毫无关系。
元素的子节点
元素可以有任意数目的子节点和后代节点。
这些子节点有可能是元素、文本节点、注释或处理指令。
Text类型
- nodeType的值为3
- nodeName的值为"#text"
- nodeValue的值为节点所包含的文本
- parentNode是一个Element
- 不支持(没有)子节点。
操作节点中的文本:
- appendData(text):将text添加到节点的末尾
- deleteData(offset,count):从offset指定的位置开始删除count个字符。
- insertData(offset,text):在offset指定的位置插入text
- replaceData(offset,count,text):用text替换从offset指定的位置开始到offset+count为止的文本。
- splitText(offset):从offset指定的位置将当前文本节点分成两个文本节点。
- substringData(offset,count):提取从offset指定的位置开始到offset+count为止的字符串。
还有个length属性
创建文本节点
document.createTextNode()方法。
规范化文本节点
normalize()方法
父节点使用,子节点中多个文本节点合并为一个。
分割文本节点
splitText()方法。
参数:一个数值代表要分割的位置。
把一个节点分为两个。
Comment类型
- nodeType的值为8
- nodeName的值为"#comment"
- nodeValue的值是注释的内容
- parentNode 可能是Document或Element
- 不支持(没有)子节点。
Coment类型与Text类型继承自相同的基类(所以,你懂的,很多前面提到的方法可以用)。
document.createComment()
CDATASection类型
只针对基于XML的文档。类似Comment,nodeType值为4。
DocumentType类型
并不常用。包含着与文档的doctype有关的所有信息。
- nodeType的值为10
- nodeName的值为doctype的名称
- nodeValue的值为null
- parentNode是Document
- 不支持(没有)子节点
DocumentFragment类型
"轻量级"文档。
- nodeType值11
- nodeName:"#document-fragment"
- nodeValue:null
- parentNode:null
- 子节点可以是:Element、ProcessingInstruction、Comment、Text、CDATASection或EntityReference。
document.createDocumentFragment()方法。
Attr类型
- nodeType:2
- nodeName:特性的名称
- nodeValue:特性的值
- parentNode:null
- 在HTML中不支持(没有)子节点。
- 在XML中子节点可以是Text或EntityReference。
3个属性:name、value、specified(布尔值,区别在代码中指定的还是默认的)。
代码演示:
var attr = document.createAttribute("align");
attr.value = "left";
element.setAttributeNode(attr);
alert(element.atrributes["align"].value); //"left"
alert(element.getAtrributeNode("align").value); //"left"
alert(element.getAtrribute("align")); //"left"
DOM操作技术
浏览器中充斥着隐藏的陷阱和不兼容问题。
动态脚本
在页面加载时不存在,但将来的某一时刻通过修改DOM动态添加的脚本。
创建动态脚本两种方式:插入外部文件和直接插入JavaScript代码。
封装的方法实现加载外部JavaScript文件:
function loadScript(url) {
var script = document.createElement("script");
script.type = "text/javascript";
script.src = url;
document.body,appendChild(script);
}
直接插入封装的函数:
function loadScriptString(code) {
var script = document.createElement("script");
script.type = "text/javascript";
try {
script.appendChild(document.createTextNode(code));
}catch(ex) {
script.text = code;
}
document.body.appendChild(script);
}
动态样式
封装的加载样式的方法:
function loadStyles(url) {
var link = document.createElement("link");
link.rel = "stylessheet";
link.type = "text/css";
link.href = url;
var head = document.getElementsByTagName("head")[0];
head.appendChild(link);
}
直接写代码封装的方法:
function loadStylesString(css) {
var style = document.createElement("style");
style.type = "text/css";
try {
style.appendChild(document.createTextNode(css));
} catch (ex) {
style.styleSheet.cssText = css;
}
var head = document.getElementsByTagName('head')[0];
head.appendChild(style);
}
操作表格
<table>
元素是HTML中最复杂的结构之一。
正常写需要冗长的代码。
使用HTMLDOM提供的方法可以简化。
例:要创建下面结构:
<table border="1" width="100%">
<tbody>
<tr>
<td>Cell 1,1</td>
<td>Cell 2,1</td>
</tr>
<tr>
<td>Cell 1,2</td>
<td>Cell 2,2</td>
</tr>
</tbody>
</table>
DOM代码:
//创建table
var table = document.createElement("table");
table.border = 1;
table.width = "100%";
//创建tbody
var tbody = document.createElement("tbody");
table.appendChild(tbody);
//创建第一行
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 2,1"));
//创建第二行
tbody.insertRow(1);
tbody.rows[1].insertCell(0);
tbody.rows[1].cells[0].appendChild(document.createTextNode("Cell 1,2"));
tbody.rows[1].insertCell(1);
tbody.rows[1].cells[1].appendChild(document.createTextNode("Cell 2,2"));
//将表格添加到文档主体中
document.body.appendChild(table);
使用NodeList
三个”动态的”集合:NameNodeMap、HTMLCollection和NodeList。
每当文档结构发生变化时,都会得到更新。