目录
一、DOM简介
DOM(文档对象模型)是针对HTML和XML文档的一个API。
DOM描绘了一个层次化的节点树,允许开发人员添加、移除和修改页面的某一部分。
W3C的DOM1级规范为基本的文档结构及查询提供了接口,DOM1级的目标主要是映射文档的结构。
二、节点层次
DOM可以将任何HTML或XML文档描绘成一个由多层节点构成的结构。
节点分为几种不同的类型,每种类型分别表示文档中不同的信息或标记。
每个节点都拥有各自的特点、数据和方法,另外也与其他节点存在某种关系。
文档节点是每个文档的根节点。
文档节点只有一个子节点,即<html>元素,称之为文档元素,文档元素是文档的最外层元素。
HTML中共有12种节点类型,这些类型都继承自一个基类型(Node类型)
三、Node类型
DOM1级定义了一个Node接口,这个Node接口在JavaScript中是作为Node类型实现的。
除了IE8及之前版本的浏览器,在其他所有浏览器中都可以访问到这个类型。
JavaScript中的所有节点类型都继承自Node类型,因此所有节点类型都共享着相同的基本属性和方法。
3.1、nodeType属性
每个节点都有一个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)
示例:
var someNode = document.getElementById("myTextbox");
if(someNode.nodeType == Node.ELEMENT_NODE){ // 在IE8及之前版本的浏览器无效
alert("Node is an element.");
}
由于IE8及之前版本的浏览器没有公开Node类型的构造函数,因此上面的代码在IE8及之前版本的浏览器中会导致错误。
为了确保跨浏览器兼容,最好还是将nodeType属性与数字值进行比较:
var someNode = document.getElementById("myTextbox");
if(someNode.nodeType == 1){ // 适用于所有浏览器
alert("Node is an element.");
}
3.2、nodeName和nodeValue属性
要了解节点的具体信息,可以使用nodeName和nodeValue这两个属性。
这两个属性的值完全取决于节点的类型。
示例:
if(someNode.nodeType == 1){
value = someNode.nodeName; //nodeName的值是元素的标签名
}
对于元素节点,nodeName中保存的始终都是元素的标签名,而nodeValue的值则始终为null。
3.3、节点关系
①childNodes属性
每个节点都有一个childNodes属性,其中保存着一个NodeList对象。
NodeList是一种类数组对象,用于保存一组有序的节点,可以通过位置来访问这些节点。
虽然可以通过方括号语法来访问NodeList的值,而且这个对象也有length属性,但它并不是Array的实例。
NodeList对象实际上是基于DOM结构动态执行查询的结果,因此DOM结构的变化能够自动反映在NodeList对象中。
NodeList是有生命、有呼吸的对象,而不是我们第一次访问它们的某个瞬间拍摄下来的一张快照。
也可以使用item()方法访问保存在NodeList中的节点:
var someNode = document.getElementById("myForm");
var firstChild = someNode.childNodes[0];
var secondChild = someNode.childNodes.item(1);
var count = someNode.childNodes.length;
②parent、nextSibling、previousSibling、firstChild和lastChild属性
每个节点都有一个parentNode属性,该属性指向文档树中的父节点。
另外,通过使用childNodes列表中的每个节点的previousSibling和nextSibling属性,可以访问同一列表中的其他节点。
列表中第一个节点的previousSibling属性的值和列表中最后一个节点的nextSibling属性的值同样也为null。
父节点的firstChild和lastChild属性分别指向其childNodes列表中的第一个和最后一个节点。
③hasChildNodes()方法
hasChildNodes()方法在节点包含一或多个子节点的情况下返回true。
这是比查询childNodes列表的length属性更简单的方法。
④ownerDocument属性
所有节点都有ownerDocument属性,该属性指向表示整个文档的文档节点。
通过这个属性,我们可以不必在节点层次中通过层层回溯到达顶端,而是可以直接访问文档节点。
3.4、操作节点
DOM提供了一些操作节点的方法:
- appendChild() —— 用于向childNodes列表的末尾添加一个节点,并返回添加的节点
- insertBefore() —— 这个方法接受两个参数:要插入的节点和作为参照的节点,插入节点后,被插入的节点会变成参照节点的前一个同胞节点,同时被方法返回。
- replaceChild() —— 这个方法接受两个参数:要插入的节点和要替换的节点。要替换的节点将由这个方法返回并从文档树中被移除,同时由要插入的节点占据其位置。
- removeChild() —— 这个方法接受一个参数,即要移除的节点。被移除的节点将成为方法的返回值。
- cloneNode() —— 用于创建调用这个方法的节点的一个完全相同的副本。cloneNode()方法接受一个布尔值参数,表示是否执行深复制。在参数为true的情况下,执行深复制,也就是复制节点及其整个子节点树;在参数为false的情况下,执行浅复制,即只复制节点本身。
// 为someNode节点插入一个子节点
var returnedNode = someNode.appendChild(newNode);
// 在someNode的子节点newNode后面插入一个节点
var returnedNode2 = someNode.insertBefore(newNode, newNode2);
// 使someNode的子节点newNode替换为newNode3
var returnedNode3 = someNode.replaceChild(newNode, newNode3);
// 移除someNode的最后一个子节点
var returnedNode4 = someNode.removeChild(someNode.lastChild);
// 深复制,同时复制了someNode的子节点
var deepNode = someNode.cloneNode(true);
// 浅复制,只复制someNode节点,不复制它的子节点
var shallowNode = someNode.cloneNode(false);
四、Document类型
JavaScript通过Document类型表示文档。
在浏览器中,document对象是HTMLDocument(继承自Document类型)的一个实例,表示整个HTML页面。
而且,document对象是window对象的一个属性,可以将其作为全局对象来访问。
Document节点具有下列特征:
- nodeType的值为9
- nodeName的值为"#document"
- nodeValue的值为null
- parentNode的值为null
- ownerDocument的值为null
- 其子节点可能是一个DocumentType(最多一个)、Element(最多一个)、ProcessingInstruction或Comment
4.1、文档的子节点
Document节点有两个内置的访问其子节点的快捷方式:
- documentElement属性 —— 指向HTML页面中的<html>元素,即文档元素
- 通过childNodes列表访问文档元素
示例:
html
<html>
<body>
</body>
</html>
js
var html = document.documentElement; // 取得对<html>的引用
console.log(html === document.childNodes[0]); // true
console.log(html === document.firstChild); // true
①document.body属性
作为HTMLDocument的实例,document对象还有一个body属性,直接指向<body>元素
示例:
var body = document.body; // 取得对<body>的引用
②document.doctype属性
Document另一个可能的子节点是DocumentType。
通常将<!DOCTYPE>标签看成一个与文档其他部分不同的实体。
可以通过document.doctype属性来访问它的信息。
示例:
var doctype = document.doctype; // 取得对<!DOCTYPE>的引用
4.2、文档信息
①document.title属性
document.title属性包含着<title>元素中的文本——显示在浏览器窗口的标题栏或标签页上。
修改title属性的值也会改变<title>元素。
示例:
// 取得文档标题
var originalTitle = document.title;
// 设置文档标题
document.title = "New page title";
②与网页请求有关的属性
以下三个属性都与对网页的请求有关:
- URL —— 包含页面完整的URL(即地址栏中显示的URL)
- domain —— 只包含页面的域名
- referrer —— 保存着链接到当前页面的那个页面的URL
URL与domain属性是相互关联的。
例如,如果document.URL等于http://www.wrox.com/WileyCDA/ ,那么document.domain就等于www.wrox.com
在这3个属性中,只有domain是可以设置的。但由于安全方面的限制,也并非可以给domain设置任何值。
如果URL中包含一个子域名,例如p2p.wrox.com,那么就只能将domain设置为父域名"wrox.com",不能将这个属性设置为URL中不包含的域。
示例:
// 假设页面来自p2p.wrox.com域
document.domain = "wrox.com"; // 设置为父域,成功!
document.domain = "nczonline.net"; // 设置为URL中不包含的域,失败!
当页面中包含来自其他子域的框架或内嵌框架时,能够设置document.domain就非常方便了。
由于跨域安全限制,来自不同子域的页面无法通过JavaScript通信。
而通过将每个页面的document.domain设置为相同的父域名的值,这些页面就可以互相访问对方包含的JavaScript对象了。
例如,假设有一个页面加载自www.wrox.com,其中包含一个内嵌框架,框架内的页面加载自p2p.wrox.com。
由于document.domain字符不一样,内外两个页面之间无法相互访问对方的JavaScript对象。
但如果将这两个页面的document.domain值都设置为"wrox.com",它们之间就可以通信了。
另外,浏览器对domain属性还有一个限制,即如果域名一开始是“松散的”,那么不能将它再设置为“紧绷的”。
示例:
// 假设页面来自于p2p.wrox.com域
document.domain = "wrox.com"; // 松散的
document.domain = "p2p.wrox.com"; // 紧绷的(出错!)
4.3、查找元素
Document类型提供了几个查找元素的方法。
- document.getElementByID() —— 取得单个元素的引用
- document.getElementsByTagName() —— 接受一个参数,即要取得元素的标签名。返回的是包含零或多个元素的HTMLCollection对象,作为一个“动态”集合,该对象与NodeList非常类似。可以使用方括号语法或item()方法来访问HTMLCollection对象中的项。另外还可以使用nameItem()方法,使用这个方法可以通过元素的name特性取得集合中的项。
- document.getElementsByName() —— 返回带有特定name特性的所有元素组成的一个NodeList。
示例:
var div = document.getElementById("mydiv");
var images = document.getElementsByTagName("img");
alert(images.length); // 输出图像的数量
alert(iamges[0].src); // 输出第一个图像的src特性
alert(images.item(0).src); // 输出第一个图像的src特性
alert(images.namedItem("myImage")); // 输出name特性为"myImage"的图像元素
var radios = document.getElementsByName("color");
4.4、特殊集合
document对象还有一些特殊的集合。这些集合都是HTMLCollection对象,为访问文档常用的部分提供了快捷方式,包括:
- document.anchors —— 包含文档中所有带name特性的<a>元素
- document.forms —— 包含文档中所有的<form>元素,与document.getElementsByTagName("form")得到的结果相同
- document.images —— 包含文档中所有的<img>元素,与document.getElementsByTagName('img')得到的结果相同
- document.links —— 包含文档中所有带href特性的<a>元素
4.5、DOM一致性检测
由于DOM分为多个级别,也包含多个部分,因此检测浏览器实现了DOM的哪些部分就十分必要了。
document.implementation属性就是为此提供相应信息和功能的对象,与浏览器对DOM的实现直接对应。
DOM1级只为document.implementation规定了一个方法,即hasFeature()。
这个方法接受两个参数:
- 要检测的DOM功能的名称
- 版本号
如果浏览器支持给定名称和版本的功能,则该方法返回true。
示例:
var hasXmlDom = document.implementation.hasFeature("XML", "1.0");
下表列出了可以检测的不同的值及版本号。
4.6、文档写入
document对象具有将输出流写入到网页中的能力,这个能力体现在下列4个方法中:
- write() —— 接受一个字符串参数,即要写入到输出流中的文本。
- writeln() —— 接受一个字符串参数,即要写入到输出流中的文本。会在字符串的末尾添加一个换行符(\n)
- open() —— 打开网页的输出流,可以用于打开一个新的浏览器窗口
- close() —— 关闭网页的输出流,可以用于关闭浏览器窗口
可以使用write()和writeln()这两个方法向页面中动态地加入内容。
示例:
<script>
document.write("<strong>" + (new Date()).toString() + "</strong>");
</script>
这个例子会创建一个DOM元素,用于输出当前日期和时间,而且可以在将来访问该元素。
此外,还可以使用write()和writeln()方法动态地包含外部资源,例如JavaScript文件等。
示例:
<script>
document.write("<script type=\"text/javascript\" src=\"file.js\">" +
"<\/script>");
</script>
注意:不能直接包含字符串"</script>",因为这会导致该字符串被解释为脚本块的结束,它后面的代码将无法执行。
另外,如果在文档加载结束后再调用document.write(),那么输出的内容将会重写整个页面。
示例:
<script>
window.onload = function(){
document.write("Hello world!");
};
</script>
五、Element类型
Element类型用于表现XML或HTML元素,提供了对元素标签名、子节点及特性的访问。
Element节点具有以下特征:
- nodeType的值为1
- nodeName的值为元素的标签名,等同于tagName属性
- nodeValue的值为null
- parentNode可能是Document或Element
- 其子节点可能是Element、Text、Comment、ProcessingInstruction、CDATASection或EntityReference
5.1、HTML元素
所有HTML元素都由HTMLElement类型表示,不是直接通过这个类型,也是通过它的子类型来表示。
HTMLElement类型继承自Element并添加了一些属性。
添加的这些属性分别对应于每个HTML元素都存在的下列标准特性:
- id —— 元素在文档中的唯一标识符
- title —— 有关元素的附加说明信息,一般通过工具提示条显示出来
- lang —— 元素内容的语言代码,很少使用
- dir —— 语言的方向,值为'ltr‘(left-to-right,从左至右)或"rtl"(right-to-left,从右向左),也很少使用。
- className —— 与元素的class特性对应
示例:
<div id="myDiv" class="abc" title="Body text" lang="en" dir="ltr"></div>
<script>
var div = document.getElementById("myDiv");
console.log(div.id); // "myDiv"
console.log(div.className); // "abc"
console.log(div.title); // "Body text"
console.log(div.lang); // "en"
console.log(div.dir); // "ltr"
</script>
也可以修改对应的每个特性:
div.id = "someOtherId";
div.className = "ft";
div.title = "Some other text";
div.lang = "fr";
div.dir = "rtl";
下表列出了所有HTML元素以及与之关联的类型:
5.2、操作特性
操作元素特性的方法主要有三个:
- getAttribute() —— 取得元素特性
- setAttribute() —— 设置元素特性
- removeAttribute() —— 删除元素特性
传递给getAttribute()的特性名与实际的特性名相同,因此要想得到class特性值,应该传入"class"而不是"className"。
特性的名称是不区分大小写的,即“ID”和"id"代表的都是同一个特性。
示例:
var value = div.getAttribute("my_special_attribute"); // 取得自定义特性值
任何元素的所有特性,都可以通过DOM元素本身的属性来访问。
但是,只有公认的(非自定义的)特性才会以属性的形式添加到DOM对象中。
示例:
html
<div id="myDiv" align="left" my_special_attribute="hello!"></div>
Js
var div = document.getElementById("myDiv");
console.log(div.id); // "myDiv"
console.log(div.my_special_attribute); // undefined
console.log(div.align); // "left"
有两类特殊的特性,它们虽然有对应的属性名,但属性的值与通过getAttribute()返回的值并不相同。
第一类特性就是style:
- 通过getAttribute()返回时,返回的style特性值中包含的是CSS文本
- 通过属性来访问它则会返回一个对象
第二类特性就是onclick这样的事件处理程序:
- 如果通过getAttribute()访问,返回相应代码的字符串
- 通过onclick属性访问,则会返回一个JavaScript函数
设置特性对应的方法是setAttribute()。
如果特性不存在,setAttribute()则创建该属性并设置相应的值。
示例:
div.setAttribute("id", "someOtherId");
注意:像下面这样为DOM元素添加一个自定义的属性,该属性不会自动成为元素的特性。
div.mycolor = "red";
console.log(div.getAttribute("mycolor")); // null
removeAttribute()方法用于彻底删除元素的特性。
调用这个方法不仅会清除特性的值,而且也会从元素中完全删除特性。
示例:
div.removeAttribute("class");
5.3、attributes属性
Element类型中的attributes属性中包含一个NamedNodeMap,与NodeList类似,也是一个“动态”的集合。
元素的每一个特性都由一个Attr节点表示,每个节点都保存在NamedNodeMap对象中。
NamedNodeMap对象拥有下列方法:
- getNamedItem(name) —— 返回nodeName属性等于name的节点
- removeNamedItem(name) —— 从列表中移除nodeName属性等于name的节点
- setNamedItem(node) —— 向列表中添加节点,以节点的nodeName属性为索引
- item(pos) —— 返回位于数字pos位置处的节点
attributes属性中包含一系列节点,每个节点的nodeName就是特性的名称,而节点的nodeValue就是特性的值。
要取得元素的id特性,可以使用以下代码:
var id = div.attributes.getNamedItem("id").nodeValue;
也可以使用方括号语法通过特性名称访问节点:
var id = div.attributes["id"].nodeValue;
可以使用这种语法来设置特性的值:
div.attributes["id"].nodeValue = "someOtherId";
调用removeNamedItem()方法与在元素上调用removeAttribute()方法的效果相同——直接删除具有给定名称的特性。
但removeNamedItem()返回表示被删除特性的Attr节点:
var oldAttr = element.attributes.removeNamedItem("id");
setNamedItem()是一个很不常用的方法,通过这个方法可以为元素添加一个新特性,为此需要为它传入一个特性节点:
element.attributes.setNamedItem(newAttr);
由于前面介绍的attributes的方法不够方便,因此开发人员更多的会使用getAttribute()、removeAttribute()和setAttribute()方法。
不过,如果想要遍历元素的特性,attributes属性倒是比较适合。
示例:
function outputAttributes(element){
var pairs = new Array(),
attrName,
attrValue;
for(var i = 0, len = element.attributes.length; i < len; i++){
attrName = element.attributes[i].nodeName;
attrValue = element.attributes[i].nodeValue;
pairs.push(attrName + "=\"" + attrValue + "\"");
}
return pairs.join(" ");
}
5.4、创建元素
使用document.createElement()方法可以创建新元素,这个方法只接受一个参数,即要创建元素的标签名。
示例:
var div = document.createElement("div");
div.id = "myNewDiv";
div.className = "box";
document.body.appendChild(div);
5.5、元素的子节点
元素的childNodes属性中包含了它的所有子节点,这些子节点有可能是元素、文本节点、注释或处理命令。
不同的浏览器在看待这些节点方面存在显著的不同。
示例:
<ul id="myList">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
如果是IE来解析这些代码,那么<ul>元素会有3个子节点,分别是3个<li>元素。
但如果是在其他浏览器中,<ul>元素都会有7个元素,包括3个<li>元素和4个文本节点(表示<li>元素之间的空白符)。
因此,如果需要通过childNodes属性遍历子节点,那么一定要在执行某项操作前,先检查一下nodeType属性。
示例:
for(var i = 0, len = element.childNodes.length; i < len; i++){
if(element.childNodes[i].nodeType == 1){ // 如果是元素节点
// 执行某些操作
}
}
另外,元素也支持getElementsByTagName()方法,以取得当前元素的所有子节点。
示例:
var ul = document.getElementById("myList");
var items = ul.getElementsByTagName("li");
六、Text类型
文本节点由Text类型表示,包含的是可以照字面解释的纯文本内容。
纯文本中可以包含转义后的HTML字符,但不能包含HTML代码。
Text节点具有以下特征:
- nodeType的值为3
- nodeName的值为“#text”
- nodeValue或data的值为节点所包含的文本
- parentNode是一个Element
- length保存着节点中字符的数目
使用下列方法可以操作节点中的文本:
- 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为止处的字符串
在取得文本节点的引用后,就可以像下面这样来修改它:
div.firstChild.nodeValue = "Some other message";
6.1、创建文本节点
可以使用document.createTextNode()创建新文本节点,这个方法接受一个参数——要插入节点中的文本。
示例:
var element = document.createElement('div');
var textNode = document.createTextNode("Hello World!");
element.appendChild(textNode);
document.body.appendChild(element);
一般情况下,每个元素只有一个文本子节点。不过在某些情况下也可能包含多个文本子节点。
示例:
var element = document.createElement('div');
var textNode = document.createTextNode("Hello World!");
element.appendChild(textNode);
var anotherTextNode = document.createTextNode("Yippee!");
element.appendChild(anotherTextNode);
document.body.appendChild(element);
如果两个文本节点是相邻的同胞节点,那么这两个节点中的文本就会连起来显示,中间不会有空格。
6.2、规范化文本节点
DOM文档中存在相邻的同胞文本节点很容易导致混乱,因为分不清哪个文本节点表示哪个字符串。
于是就催生了一个能将相邻文本节点合并的方法normalize(),这个方法是由Node类型定义的(因而在所有节点类型中都存在)。
如果在一个包含两个或多个文本节点的父元素上调用normalize()方法,则会将所有文本节点合并成一个节点。
结果节点的nodeValue等于将合并前每个文本节点的nodeValue值拼接起来的值。
示例:
var element = document.createElement('div');
var textNode = document.createTextNode("Hello World!");
element.appendChild(textNode);
var anotherTextNode = document.createTextNode("Yippee!");
element.appendChild(anotherTextNode);
document.body.appendChild(element);
console.log(element.childNodes.length); // 2
element.normalize();
console.log(element.childNodes.length); // 1
console.log(element.firstChild.nodeValue); // "Hello world!Yippee!"
6.3、分割文本节点
Text类型提供了一个作用与normalize()相反的方法:splitText()。
这个方法会将一个文本节点分成两个文本节点,即按照指定的位置分割nodeValue值。
原来的文本节点将包含从开始到指定位置之前的内容,新文本节点将包含剩下的文本。
这个方法会返回一个新文本节点,该节点与原节点的parentNode相同。
var element = document.createElement('div');
var textNode = document.createTextNode("Hello World!");
element.appendChild(textNode);
document.body.appendChild(element);
var newNode = element.firstChild.splitText(5);
console.log(element.firstChild.nodeValue); // "Hello"
console.log(newNode.nodeValue); // " world!"
console.log(element.childNodes.length); // 2
七、Comment类型
注释在DOM中是通过Comment类型来表示的。
Comment节点具有下列特征:
- nodeType的值为8
- nodeName的值为"#comment"
- nodeValue或data的值是注释的内容
- parentNode可能是Document或Element
- 不支持(没有)子节点
Comment类型与Text类型继承自相同的基类,因此它拥有除splitText()之外的所有字符串操作方法。
注释节点可以通过其父节点来访问。
示例:
html
<div id="myDiv"><!-- A Comment --></div>
JS
var div = document.getElementById("myDiv");
var comment = div.firstChild;
console.log(comment.data); // "A comment"
另外,使用document.createComment()并为其传递注释文本也可以创建注释节点
示例:
var comment = document.createComment("A comment ");
开发人员很少会创建和访问注释节点,因为注释节点对算法鲜有影响。
此外,浏览器也不会识别位于</html>标签后面的注释。
八、CDATASection类型
九、DocumentType类型
DocumentType包含着与文档的doctype有关的所有信息,它具有下列特征:
- nodeType的值为10
- nodeName的值为doctype的名称
- nodeValue的值为null
- parentNode是Document
- 不支持(没有)子节点
在DOM1级中,DocumentType对象不能动态创建,而只能通过解析文档代码的方式来创建。
支持它的浏览器会把DocumentType对象保存在document.doctype中。
DOM1级描述了DocumentType对象的3个属性:
- name —— 表示文档类型的名称
- entities —— 由文档类型描述的实体的NamedNodeMap对象
- notations —— 由文档类型描述的符号的NamedNodeMap对象。
浏览器中的文档使用的都是HTML或XHTML文档类型,因而entities和notations都是空列表(列表中的项来自行内文档类型声明)。
只有name属性是有用的,这个属性中保存的是文档类型的名称,也就是出现在<!DOCTYPE之后的文本。
以下面严格型HTML 4.01的文档类型声明为例:
DocumentType的name属性中保存的就是"HTML":
alert(document.doctype.name); // "HTML"
十、DocumentFragment类型
在所有节点类型中,只有DocumentFragment在文档中没有对应的标记。
DOM规定文档片段是一种”轻量级“的文档,可以包含和控制节点,但不会像完整的文档那样占用额外的资源。
DocumentFragment节点具有下列特征:
- nodeType的值为11
- nodeName的值为"#document-fragment"
- nodeValue的值为null
- parentNode的值为null
- 子节点可以是Element、ProcessingInstruction、Comment、Text、CDATASection或EntityReference
虽然不能把文档片段直接添加到文档中,但可以将它作为一个”仓库“来使用,即可以在里面保存将来可能会添加到文档中的节点。
要创建文档片段,可以使用document.createDocumentFragment()方法。
示例:
var fragment = document.createDocumentFragment();
文档片段继承了Node的所有方法,通常用于执行那些针对文档的DOM操作。
如果将文档中的节点添加到文档片段中,就会从文档树中移除该节点,也不会从浏览器中再看到该节点。
添加到文档片段中的新节点同样也不属于文档树。
可以通过appendChild()或insertBefore()将文档片段中内容添加到文档中。
在将文档片段作为参数传递给这两个方法时,实际上只会将文档片段的所有子节点添加到相应位置上,文档片段本身永远不会成为文档树的一部分。
示例:
html
<ul id="myList"></ul>
想为这个<ul>元素添加3个列表项,如果逐个地添加列表项,将会导致浏览器反复渲染(呈现)新信息。
为避免这个问题,可以像下面这样使用一个文档片段来保存创建的列表项,然后再一次性将它们添加到文档中:
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.appendChild(fragment);
十一、Attr类型
元素的特性在DOM中以Attr类型来表示。
从技术角度讲,特性就是存在于元素的attributes属性中的节点。
特性节点具有下列特征:
- nodeType的值为2
- nodeName的值是特性的名称
- nodeValue的值是特性的值
- parentNode的值为null
- 在HTML中不支持(没有)子节点
- 在XML中子节点可以是Text或EntityReference
Attr对象有3个属性:
- name —— 特性名称(与nodeName的值相同)
- value —— 特性的值(与nodeValue的值相同)
- specified —— 布尔值,用以区别特性是在代码中指定的,还是默认的。
使用document.createAttribute()并传入特性的名称可以创建新的特性节点。
示例:
要为元素添加align特性,可以使用下列代码:
var attr = document.createAttribute("align");
attr.value = "left";
element.setAttributeNode(attr);
console.log(element.attributes['align'].value); // "left"
console.log(element.getAttributeNode('align').value) // "left"
console.log(element.getAttribute('align')); // "left"
getAttributeNode()方法用于获取元素的特性节点。
setAttributeNode()方法用于设置元素的特性节点。