节点层次
Node类型
DOM1 级定义了一个 Node 接口,该接口将由 DOM 中的所有节点类型实现。每个节点都有一个 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)。
-
nodeName 和 nodeValue 属性
使用nodeName和nodeValue属性可以了解节点的具体信息。对于元素节点,nodeName 中保存的始终都是元素的标签名,而 nodeValue 的值则始终为 null
-
节点关系
- 每个节点都有一个 childNodes 属性,其中保存着一个 NodeList 对象(可以通过方括号语法来访问 NodeList 的值,这个对象也有 length 属性—— 表示的是访问 NodeList 的那一刻,其中包含的节点数量)。NodeList对象是基于DOM结构动态执行查询的结果,可以通过方括号和item()访问节点
var firstChild = someNode.childNodes[0]; var secondChild = someNode.childNodes.item(1); var count = someNode.childNodes.length;- 每个节点都有一个 parentNode 属性,指向文档树中的父节点。
- 每个节点都有的 previousSibling和 nextSibling 属性,分别指向上一个节点和下一个节点。列表中第一个节点的 previousSibling 属性值为 null,而列表中最后一个节点的 nextSibling 属性的值同样也为 null。
- 父节点的 firstChild 和 lastChild属性分别指向其 childNodes 列表中的第一个和最后一个节点。
- 所有节点都有的最后一个属性是 ownerDocument,该属性指向表示整个文档的文档节点。任何节点都属于它所在的文档,任何节点都不能同时存在于两个或更多个文档中。
-
操作节点
操作的是某个节点的子节点,也就是说,要使用这几个方法必须先取得父节点(使用 parentNode 属性)。另外,并不是所有类型的节点都有子节点,如果在不支持子节点的节点上调用了这些方法,将会导致错误发生。
- appendChild():向childNodes列表末尾添加一个节点。添加节点后,childNodes 的新增节点、父节点及以前的最后一个子节点的关系指针都会相应地得到更新,更新完成后,appendChild()返回新增的节点。如果传入到 appendChild()中的节点已经是文档的一部分了,那结果是将该节点从原来的位置转移到末尾。例如在调用 appendChild()时传入了父节点的第一个子节点,那么该节点就会成为父节点的最后一个子节点。
- insertBefore():把节点放在 childNodes 列表中某个特定的位置上。两个参数:要插入的节点和作为参照的节点。插入节点后,被插入的节点会变成参照节点的前一个同胞节点,同时被方法返回。如果参照节点是null,则 insertBefore()与 appendChild()执行相同的操作
- replaceChild():替换节点。两个参数:要插入的节点和要替换的节点。要替换的节点将由这个方法返回并从文档树中被移除,同时由要插入的节点占据其位置。
- removeChild():移除节点。一个参数:要移除的节点
-
其他方法
这些方法是所有节点共有的。
- cloneNode():用于创建调用这个方法的节点的一个完全相同的副本,不会复制添加到 DOM 节点中的 JavaScript 属性。接收一个布尔值参数,表示是否进行深复制,值为true时执行深复制,也就是复制节点及其整个子节点树;值为false时执行浅复制,只复制节点本身。复制后返回的节点副本属于文档所有,但并没有为它指定父节点。
- normalize():处理文档树中的文本节点。
Document类型
-
文档的子节点
- document.documentElement:指向<html>元素
- document.body:指向<body>元素
- document.doctype:指向<!DOCTYPE>标签
-
文档信息
- document.title:包含着<title>元素中的文本——显示在浏览器窗口的标题栏或标签页上。通过这个属性可以取得当前页面的标题,也可以修改当前页面的标题并反映在浏览器的标题栏中
- document.URL:包含页面完整的 URL(即地址栏中显示的 URL),不可设置。
- document.domain:包含页面的域名,可设置。将每个页面的document.domain 设置为相同的值,这些页面就可以互相访问对方包含的 JavaScript 对象了。域名一开始是“松散的”(loose),那么不能将它再设置为“紧绷的”(tight)。例如,在将 document.domain 设置为"wrox.com"之后,就不能再将其设置回"p2p.wrox.com",否则将会导致错误
- document.referrer:保存链接到当前页面的那个页面的 URL,不可设置。在没有来源页面的情况下,referrer 属性中可能会包含空字符串
-
查找元素
-
getElementById():不存在匹配的元素时返回null,有多个匹配结果时返回第一个元素
-
getElementByTagName():返回一个HTMLCollection 对象。HTMLCollection 对象namedItem()方法,该方法可以通过元素的 name特性取得集合中的项。对命名的项也可以使用方括号语法来访问
<img src="myimage.gif" name="myImage"> var images = document.getElementsByTagName("img"); //myImage1和myImage2表示同一个DOM对象 var myImage1 = images.namedItem("myImage"); var myImage2 = images["myImage"]; -
getElementsByName():返回带有给定 name 特性的所有元素
-
-
特殊集合
- document.anchors:包含文档中所有带 name 特性的<a>元素;
- document.forms:包含文档中所有的<form>元素,与 document.getElementsByTagName("form")得到的结果相同;
- document.images:包含文档中所有的<img>元素,与 document.getElementsByTagName ("img")得到的结果相同;
- document.links:包含文档中所有带 href 特性的<a>元素。
-
DOM 一致性检测
DOM1 级只为 document.implementation 规定了一个方法,即 hasFeature()。这个方法接受两个参数:要检测的 DOM 功能的名称及版本号。如果浏览器支持给定名称和版本的功能,则该方法返回 true
var hasXmlDom = document.implementation.hasFeature("XML", "1.0");
-
文档写入
- document.write():写入到输出流,原样写入
- document.writeln():写入到输出流,末尾添加一个换行符(\n)
- document.open():打开网页的输出流
- docum.close():关闭网页的输出流
Element类型
-
特性相关方法
- getAttribute():取得特性。取得自定义的特性值使用该方法,取得公认的特性值的时候直接使用对象的属性获取
- setAttribute():设置特性。接受两个参数:要设置的特性名和值。如果特性已经存在,setAttribute()会以指定的值替换现有的值;如果特性不存在,setAttribute()则创建该属性并设置相应的值。直接给属性赋值可以设置特性的值,但是为 DOM 元素添加一个自定义的属性,该属性不会自动成为元素的特性
- removeAttribute():删除特性。不仅清除特性的值,而且会从元素中完全删除特性
-
attributes属性
- getNamedItem(name):返回 nodeName 属性等于 name 的节点;
- removeNamedItem(name):从列表中移除 nodeName 属性等于 name 的节点;
- setNamedItem(node):向列表中添加节点,以节点的 nodeName 属性为索引;
- item(pos):返回位于数字 pos 位置处的节点。
attributes 属性中包含一系列节点,每个节点的 nodeName 就是特性的名称,而节点的 nodeValue就是特性的值。要取得元素的 id 特性,可以使用以下代码
var id = element.attributes.getNamedItem("id").nodeValue;, 使用方括号语法访问节点var id = element.attributes["id"].nodeValue;,也可以使用这种语法来设置特性的值,即先取得特性节点,然后再将其 nodeValue 设置为新值,如下所示。element.attributes["id"].nodeValue = "someOtherId"; -
创建元素
document.createElement():接受一个参数,要创建元素的标签。
var div1 = document.createElement("div"); div1.id = "myNewDiv"; div1.className = "box"; document.body.appendChild(div); //在IE中可以以另一种方式使用 createElement() var div2 = document.createElement("\<div id=\"myNewDiv\" class=\"box\">\</div >");
Text类型
文本节点由 Text 类型表示,包含的是可以照字面解释的纯文本内容。纯文本中可以包含转义后的HTML 字符,但不能包含 HTML 代码。
-
创建文本节点
document.createTextNode():创建文本节点。接受一个参数:要插入节点中的文本。新建之后需要把文本节点添加到文档树中已经存在的节点中
var element = document.createElement("div"); element.className = "message"; var textNode = document.createTextNode("Hello world!"); element.appendChild(textNode); document.body.appendChild(element); -
规范化文本节点
normalize():将所有文本节点合并成一个节点,结果节点的 nodeValue 等于将合并前每个文本节点的 nodeValue 值拼接起来的值。
var element = document.createElement("div"); element.className = "message"; var textNode = document.createTextNode("Hello world!"); element.appendChild(textNode); var anotherTextNode = document.createTextNode("Yippee!"); element.appendChild(anotherTextNode); document.body.appendChild(element); alert(element.childNodes.length); //2 element.normalize(); alert(element.childNodes.length); //1 alert(element.firstChild.nodeValue); // "Hello world!Yippee!" -
分割文本节点
splitText():分割文本节点。接收一个参数:要开始分割的位置。将一个文本节点分成两个文本节点,即按照指定的位置分割 nodeValue 值。
var element = document.createElement("div"); element.className = "message"; var textNode = document.createTextNode("Hello world!"); element.appendChild(textNode); document.body.appendChild(element); var newNode = element.firstChild.splitText(5); alert(element.firstChild.nodeValue); //"Hello" alert(newNode.nodeValue); //" world!" alert(element.childNodes.length); //2
Comment类型
注释在 DOM 中是通过 Comment 类型来表示的。可以通过 nodeValue 或 data 属性来取得注释的内容
document.createComment():创建注释节点,传递注释文本
CDATASection类型
CDATASection 类型只针对基于 XML 的文档,表示的是 CDATA 区域。
document.createCDataSection():创建 CDATA 区域
DocumentType类型
DocumentType包含着与文档的 doctype 有关的所有信息
- document.doctype.name:文档类型的名称
- document.doctype.entities:由文档类型描述的实体的 NamedNodeMap 对象
- document.doctype.notations:由文档类型描述的符号的NamedNodeMap 对象
DocumentFragment类型
DocumentFragment是一种“轻量级”的文档,可以包含和控制节点,可以将它作为一个“仓库”来使用,即可以在里面保存将来可能会添加到文档中的节点
document.createDocumentFragment():创建文档片段
<ul id="myList"></ul>
//使用一个文档片段来保存创建的列表项,然后再一次性将它们添加到文档中。
var fragment = document.createDocumentFragment();
var ul = document.getElementById("myList");
var li = null;
for (var i=0; i \< 3; i++){
li = document.createElement("li");
li.appendChild(document.createTextNode("Item " + (i+1)));
fragment.appendChild(li);
}
//文档片段的所有子节点都被删除并转移到了\<ul>元素中
ul.appendChild(fragment);
Attr类型
元素的特性在 DOM 中以 Attr 类型来表示。
Attr 对象有 3 个属性:name、value 和 specified。其中,name 是特性名称(与 nodeName 的值相同),value 是特性的值(与 nodeValue 的值相同),而 specified 是一个布尔值,用以区别特性是在代码中指定的,还是默认的。
DOM操作技术
动态脚本
两种方式:插入外部文件和直接插入 JavaScript 代码
//插入外部文件
function loadScript(url){
var script = document.createElement("script");
script.type = "text/javascript";
script.src = url;
document.body.appendChild(script);
}
//调用
loadScript("client.js");
//直接插入js代码
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);
}
//调用
loadScrptStrng("uncton sayH(){alert('h');}")
动态样式
<link>元素用于包含来自外部的文件,<style>元素用于指定嵌入的样式。
//外部文件样式
function loadStyles(url){
var link = document.createElement("link");
link.rel = "stylesheet";
link.type = "text/css";
link.href = url;
var head = document.getElementsByTagName("head")[0];
head.appendChild(link);
}
loadStyles("styles.css");
//嵌入样式
function loadStyleString(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);
}
loadStyleString("body{background-color:red}");
操作表格
为了方便构建表格,HTML DOM 还为<table>、<tbody>和<tr>元素添加了一些属性和方法。
为<table>元素添加的属性和方法如下:
- caption:保存着对<caption>元素(如果有)的指针。
- tBodies:是一个<tbody>元素的 HTMLCollection。
- tFoot:保存着对<tfoot>元素(如果有)的指针。
- tHead:保存着对<thead>元素(如果有)的指针。
- rows:是一个表格中所有行的 HTMLCollection。
- createTHead():创建<thead>元素,将其放到表格中,返回引用。
- createTFoot():创建<tfoot>元素,将其放到表格中,返回引用。
- createCaption():创建<caption>元素,将其放到表格中,返回引用。
- deleteTHead():删除<thead>元素。
- deleteTFoot():删除<tfoot>元素。
- deleteCaption():删除<caption>元素。
- deleteRow(pos):删除指定位置的行。
- insertRow(pos):向 rows 集合中的指定位置插入一行。
为<tbody>元素添加的属性和方法如下:
- rows:保存着<tbody>元素中行的 HTMLCollection。
- deleteRow(pos):删除指定位置的行。
- insertRow(pos):向 rows 集合中的指定位置插入一行,返回对新插入行的引用。
为<tr>元素添加的属性和方法如下:
- cells:保存着<tr>元素中单元格的 HTMLCollection。
- deleteCell(pos):删除指定位置的单元格。
- insertCell(pos):向 cells 集合中的指定位置插入一个单元格,返回对新插入单元格的引用。
//创建 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
NodeList 及其“近亲”NamedNodeMap 和 HTMLCollection,这三个集合都是“动态的”;换句话说,每当文档结构发生变化时,它们都会得到更新。浏览器不会将创建的所有集合都保存在一个列表中,而是在下一次访问集合时再更新集合。
//不能这样做,会导致死循环
var divs = document.getElementsByTagName("div"),
i,
div;
for (i=0; i < divs.length; i++){
div = document.createElement("div");
document.body.appendChild(div);
}
var divs = document.getElementsByTagName("div"),
i,
len,
div;
for (i = 0, len = divs.length; i < len; i++){
div = document.createElement("div");
document.body.appendChild(div);
}
这个例子中初始化了第二个变量 len。由于 len 中保存着对 divs.length 在循环开始时的一个快照,因此就会避免出现无限循环问题。