DOM
DOM 表示由多层节点构成的文档,通过它开发者可以添加、删除和修改页面的各个部分。
节点层级
<html>
<head>
<title>Sample Page</title>
</head>
<body>
<p>Hello World!</p>
</body>
</html>
对应的层级结构:
document 节点表示每个文档的根节点。在这里,根节点的唯一子节点是元素,我们称之为文档元素(documentElement)。文档元素是文档最外层的元素,每个文档只能有一个文档元素。在 HTML 页面中,文档元素始终是元素。在 XML 文档中,则没有这样预定义的元素,任何元素都可能成为文档元素。DOM 中总共有 12 种节点类型,这些类型都继承一种基本类型。
Node 类型
Node 接口在 JavaScript中被实现为 Node 类型,在除 IE之外的所有浏览器中都可以直接访问这个类型。在 JavaScript中,所有节点类型都继承 Node 类型,因此所有类型都共享相同的基本属性和方法。
每个节点都有 nodeType 属性,表示该节点的类型。节点类型由定义在 Node 类型上的 12 个数值常量表示:
Node.ELEMENT_NODE(1) //元素结点,像html.body,<标签名>这些都是
Node.ATTRIBUTE_NODE(2) //结点的属性,像div.id , div.class这些的nodeType就是2
Node.TEXT_NODE(3) //文本结点
Node.CDATA_SECTION_NODE(4) //XML 中特有的 CDATA 区块,继承自 Text 类型
Node.ENTITY_REFERENCE_NODE(5) //
Node.ENTITY_NODE(6) //
Node.PROCESSING_INSTRUCTION_NODE(7) //
Node.COMMENT_NODE(8) //comment类型,就是注释
Node.DOCUMENT_NODE(9) //Document 类型
Node.DOCUMENT_TYPE_NODE(10) //DocumentType类型,就是<!doctype>这个标签
Node.DOCUMENT_FRAGMENT_NODE(11) //定义为“轻量级”文档,给不在文档树的结点充当文档仓库
Node.NOTATION_NODE(12) //
浏览器并不支持所有节点类型。开发者最常用到的是元素节点和文本节点。本章后面会讨论每种节点受支持的程度及其用法。
- nodeName 与 nodeValue
nodeName 与 nodeValue 保存着有关节点的信息。这两个属性的值完全取决于节点类型。在使用这两个属性前,最好先检测节点类型,如下所示:
if (someNode.nodeType == 1){
value = someNode.nodeName; // 会显示元素的标签名
}
在这个例子中,先检查了节点是不是元素。如果是,则将其 nodeName 的值赋给一个变量。对元素而言,nodeName 始终等于元素的标签名,而 nodeValue 则始终为 null
-
节点关系
每个节点都有一个 childNodes 属性,其中包含一个 NodeList 的实例。NodeList 是一个类数组对象,用于存储可以按位置存取的有序节点。
每个节点都有一个 parentNode 属性,指向其 DOM 树中的父元素。
此外,childNodes 列表中的每个节点都是同一列表中其他节点的同胞节点。而使用 previousSibling 和 nextSibling 可以在这个列表的节点间导航。这个列表中第一个节点的 previousSibling 属性是 null,最后一个节点的nextSibling 属性也是 null,如下所示:if (someNode.nextSibling === null){ //如果没有下一个同胞结点,那么在兄弟结点中,就是最后一个结点 alert("Last node in the parent's childNodes list."); } else if (someNode.previousSibling === null){ //如果没有上一个同胞结点,那么在兄弟结点中,就是第一个结点 alert("First node in the parent's childNodes list."); }
所以:如果 childNodes 中只有一个节点,则它的 previousSibling 和 nextSibling 属性都是null。
父节点和它的第一个及最后一个子节点也有专门属性:firstChild 和 lastChild 分别指向childNodes 中的第一个和最后一个子节点。
利用这些关系指针,几乎可以访问到文档树中的任何节点。
hasChildNodes():true 则说明节点有一个或多个子节点。相比查询childNodes 的 length 属性,这个方法无疑更方便。
最后还有一个所有节点都共享的关系。ownerDocument 属性是一个指向代表整个文档的文档节点的指针。 -
操纵节点
最常用的方法是appendChild(),用于在 childNodes 列表末尾添加节点。添加新节点会更新相关的关系指针,包括父节点和之前的最后一个子节点。appendChild()方法返回新添加的节点。
如果把文档中已经存在的节点传给 appendChild(),则这个节点会从之前的位置被转移到新位置。即使 DOM 树通过各种关系指针维系,一个节点也不会在文档中同时出现在两个或更多个地方。因此,如果调用 appendChild()传入父元素的第一个子节点,则这个节点会成为父元素的最后一个子节点。
那么问题来了:如何把结点插入childNodes 中的特定位置?
使用 insertBefore()方法=>两个参数:要插入的节点和参照节点。要插入的节点会变成参照节点的前一个同胞节点,并被返回。如果参照节点是 null,则 insertBefore()与 appendChild()效果相同,如下面的例子所示:
// 作为最后一个子节点插入
returnedNode = someNode.insertBefore(newNode, null);
alert(newNode == someNode.lastChild); // true
// 作为新的第一个子节点插入
returnedNode = someNode.insertBefore(newNode, someNode.firstChild);
alert(returnedNode == newNode); // true
alert(newNode == someNode.firstChild); // true
// 插入最后一个子节点前面
returnedNode = someNode.insertBefore(newNode, someNode.lastChild);
alert(newNode == someNode.childNodes[someNode.childNodes.length - 2]); // true
相对地,replaceChild()方法接收两个参数:要插入的节点和要替换的节点。要替换的节点会被返回并从文档树中完全移除,要插入的节点会取而代之。
要移除节点而不是替换节点,可以使用 removeChild()方法。这个方法接收一个参数,即要移除的节点。被移除的节点会被返回。
(与 replaceChild()方法一样,通过 removeChild()被移除的节点从技术上说仍然被同一个文档所拥有,但文档中已经没有它的位置。)
-
其他方法
第一个是 cloneNode(),会返回与调用它的节点一模一样的节点。cloneNode()方法接收一个布尔值参数,表示是否深复制。在传入 true 参数时,会进行深复制,即复制节点及其整个子 DOM 树。如果传入 false,则只会复制调用该方法的节点。复制返回的节点属于文档所有,但尚未指定父节点,所以可称为孤儿节点(orphan)。可以通过 appendChild()、insertBefore()或 replaceChild()方法把孤儿节点添加到文档中。- item 1
- item 2
- item 3
//如果myList保存着对这个
- 元素的引用,则下列代码展示了使用cloneNode()方法的两种方式:
let deepList = myList.cloneNode(true);
alert(deepList.childNodes.length); // 3(IE9 之前的版本)或 7(其他浏览器)
let shallowList = myList.cloneNode(false);
alert(shallowList.childNodes.length); // 0
Tips:cloneNode()方法不会复制添加到 DOM 节点的 JavaScript 属性,比如事件处理程序。这个方法只复制 HTML 属性,以及可选地复制子节点。除此之外则一概不会复制。IE 在很长时间内会复制事件处理程序,这是一个 bug,所以推荐在复制前先删除事件处理程序。
最后一个方法是 normalize()。这个方法唯一的任务就是处理文档子树中的文本节点。由于解析器实现的差异或 DOM 操作等原因,可能会出现并不包含文本的文本节点,或者文本节点之间互为同胞关系。在节点上调用 normalize()方法会检测这个节点的所有后代,从中搜索上述两种情形。如果发现空文本节点,则将其删除;如果两个同胞节点是相邻的,则将其合并为一个文本节点。
### Document 类型
在浏览器中,文档对象 document 是HTMLDocument 的实例(HTMLDocument 继承 Document),表示整个 HTML 页面。
Document 类型的节点有以下特征:
nodeType 等于 9;
nodeName 值为"#document";
nodeValue 值为 null;
parentNode 值为 null;
ownerDocument 值为 null;
子节点可以是 DocumentType(最多一个)、Element(最多一个)、ProcessingInstruction或 Comment 类型。
1. 文档子节点
第一个是 documentElement 属性,始终指向 HTML 页面中的<html>元素:
console.log(document.documentElement)
//返回的是页面html结点
document 对象还有一个 body 属性,直接指向<body>元素
document 对象可以通过 doctype 属性(在浏览器中是document.doctype)来访问子节点是 DocumentType,即:<!doctype>标签是文档中独立的部分
另外,严格来讲出现在<html>元素外面的注释也是文档的子节点,它们的类型是 Comment。不过,由于浏览器实现不同,这些注释不一定能被识别,或者表现可能不一致。比如以下 HTML 页面:
//该页面的document有四个子结点:<!DOCTYPE html>、注释、元素、注释
<!DOCTYPE html>
但实际上,浏览器有可能以不同方式对待<html>元素外部的注释,例如我的电脑谷歌浏览器,只会读取第一条,后面的注释会忽略掉
console.log(document.childNodes)
// NodeList(3) [<!DOCTYPE html>, comment, html#html]
2. 文档信息
第一个属性是 title,包含<title>元素中的文本,通常显示在浏览器窗口或标签页的标题栏。通过这个属性可以读写页面的标题,修改后的标题也会反映在浏览器标题栏上。不过,修改 title 属性并不会改变<title>元素。
第二个属性是URL,包含当前页面的完整 URL(地址栏中的 URL)
第三个属性是domain,包含页面的域名
第四个属性是referrer,包含链接到当前页面的那个页面的 URL。如果当前页面没有来源,则 referrer 属性包含空字符串。
所有这些信息都可以在请求的 HTTP 头部信息中获取,只是在 JavaScript 中通过这几个属性暴露出来而已。
(在这些属性中,**只有 domain 属性是可以设置的**。出于安全考虑,给 domain 属性设置的值是有限制的。如果 URL包含子域名如 p2p.wrox.com,则可以将 domain 设置为"wrox.com"(URL包含“www”时也一样,比如 www.wrox.com)。不能给这个属性设置 URL 中不包含的值),比如:
// 页面来自 p2p.wrox.com
document.domain = "wrox.com"; // 成功
document.domain = "nczonline.net"; // 出错!
//浏览器对 domain 属性还有一个限制,即这个属性一旦放松就不能再收紧。
document.domain = "wrox.com"; // 放松,成功
document.domain = "p2p.wrox.com"; // 收紧,错误!
当页面中包含来自某个不同子域的窗格(<frame>)或内嵌窗格(<iframe>)时,设置document.domain 是有用的。因为跨源通信存在安全隐患,所以不同子域的页面间无法通过 JavaScript通信。此时,在每个页面上把 document.domain 设置为相同的值,这些页面就可以访问对方的 JavaScript对象了。
比如,一个加载自 www.wrox.com 的页面中包含一个内嵌窗格,其中的页面加载自p2p.wrox.com。这两个页面的 document.domain 包含不同的字符串,内部和外部页面相互之间不能访问对方的 JavaScript 对象。如果每个页面都把 document.domain 设置为 wrox.com,那这两个页面之间就可以通信了。
3. 定位元素
第一个方法getElementById()方法接收一个参数,即要获取元素的 ID如果找到了则返回这个元素,如果没找到则返回 null。
第二个方法getElementsByTagName()接收一个参数,即要获取元素的标签名,返回包含零个或多个元素的 NodeList。
在 HTML 文档中,这个方法返回一个HTMLCollection 对象。考虑到二者都是“实时”列表,HTMLCollection 与 NodeList 是很相似的。
HTMLCollection 对象还有一个额外的方法 namedItem(),可通过标签的 name 属性取得某一项的引用。例如,假设页面中包含如下元素:
//那么也可以像这样从 images 中取得对这个元素的引用:
let images = document.getElementsByTagName("img"); //HTMLCollection [img, myImage: img]
let myImage = images.namedItem("myImage"); //
console.log(images[0] === myImage) //true
要取得文档中的所有元素,可以给 getElementsByTagName()传入*。在 JavaScript 和 CSS 中,*一般被认为是匹配一切的字符。
返回包含页面中所有元素的 HTMLCollection 对象,顺序就是它们在页面中出现的顺序。
第三个方法getElementsByName(),这个方法会返回具有给定 name 属性的所有元素。与 getElementsByTagName()一样,getElementsByName()方法也返回 HTMLCollection。最常用于单选按钮,因为同一字段的单选按钮必须具有相同的 name 属性才能确保把正确的值发送给服务器
4. 特殊集合
document 对象上还暴露了几个特殊集合,这些集合也都是 HTMLCollection 的实例。这些集合是访问文档中公共部分的快捷方式。
5. DOM 兼容性检测
document.implementation 属性是一个对象,其中提供了与浏览器 DOM 实现相关的信息和能力。
6. 文档写入
document 对象有一个古老的能力,即向网页输出流中写入内容。这个能力对应 4 个方法:write()、writeln()、open()和 close()。
write()和 writeln()方法都接收一个字符串参数,可以将这个字符串写入网页中。write()简单地写入文本,而 writeln()还会在字符串末尾追加一个换行符
(\n)。这两个方法可以用来在页面加载期间向页面中动态添加内容,经常用于动态包含外部资源:
document.write("<script type=\"text/javascript\" src=\"file.js\">" + "<\/script>"); **\/script**包含转义字符,否则匹配最外层script
但:如果是在页面加载完之后再调用 document.write(),则输出的内容会重写整个页面!
(open()和 close()方法分别用于打开和关闭网页输出流。在调用 write()和 writeln()时,这两个方法都不是必需的)
### Element 类型
除了Document 类型,Element 类型就是Web开发中最常用的类型了。**Element 表示XML或HTML元素**,对外暴露出访问元素标签名、子节点和属性的能力。Element 类型的节点具有以下特征:
nodeType 等于 1;
nodeName 值为元素的标签名;
nodeValue 值为 null;
parentNode 值为 Document 或 Element 对象;
子节点可以是 Element、Text、Comment、ProcessingInstruction、CDATASection、EntityReference 类型。
在 HTML 中,元素标签名始终以全大写表示;在 XML(包括 XHTML)中,标签名始终与源代码中的大小写一致。如果不确定脚本是在 HTML 文档还是 XML 文档中运行,最好将标签名转换为小写形式,以便于比较:
if (element.tagName == "div"){ // 不要这样做,可能出错!
// do something here
}
if (element.tagName.toLowerCase() == "div"){ // 推荐,适用于所有文档
// 做点什么
}
1. HTML 元素
所有 HTML 元素都通过 HTMLElement 类型表示,包括其直接实例和间接实例。HTMLElement直接继承 Element 并增加了一些属性。
id,元素在文档中的唯一标识符;
title,包含元素的额外信息,通常以提示条形式展示;
lang,元素内容的语言代码(很少用);
dir,语言的书写方向("ltr"表示从左到右,"rtl"表示从右到左,同样很少用);
className,相当于 class 属性,用于指定元素的 CSS 类(因为 class 是 ECMAScript 关键字,所以不能直接用这个名字)。
所有这些都可以用来获取对应的属性值,也可以用来修改相应的值。
所有 HTML 元素都是 HTMLElement 或其子类型的实例。
2. 取得属性
与属性相关的 DOM 方法主要有 3 个:getAttribute()、setAttribute()和 removeAttribute()。这些方法主要用于操纵属性,包括在 HTMLElement 类型上定义的属性。下面看一个例子:
let div = document.getElementById("myDiv");
//如果给定的属性不存在,则 getAttribute()返回 null。getAttribute()方法也能取得不是 HTML 语言正式属性的自定义属性的值。
alert(div.getAttribute("id")); // "myDiv"
alert(div.getAttribute("class")); // "bd"
alert(div.getAttribute("title")); // "Body text"
alert(div.getAttribute("lang")); // "en"
alert(div.getAttribute("dir")); // "ltr"
通过 DOM 对象访问的属性中有两个返回的值跟使用 getAttribute()取得的值不一样。首先是style 属性,这个属性用于为元素设定 CSS 样式。在使用 getAttribute()访问 style 属性时,返回的是 CSS 字符串。而在通过 DOM 对象的属性访问时,style 属性返回的是一个(CSSStyleDeclaration)对象。DOM 对象的 style 属性用于以编程方式读写元素样式,因此不会直接映射为元素中 style 属性的字符串值。
第二个属性其实是一类,即事件处理程序(或者事件属性),比如 onclick。在元素上使用事件属性时(比如 onclick),属性的值是一段 JavaScript 代码。如果使用 getAttribute()访问事件属性,则返回的是字符串形式的源代码。而通过 DOM 对象的属性访问事件属性时返回的则是一个 JavaScript函数(未指定该属性则返回 null)。这是因为 onclick 及其他事件属性是可以接受函数作为值的。
考虑到以上差异,开发者在进行DOM编程时通常会放弃使用getAttribute()而只使用对象属性。getAttribute()主要用于取得自定义属性的值。
3. 设置属性
setAttribute()是getAttribute()配套的方法,接收两个参数:要设置的属性名和属性的值。(存在则替换,否则新建)
因为元素属性也是 DOM 对象属性,所以直接给 DOM 对象的属性赋值也可以设置元素属性的值,如下所示:
div.id = "someOtherId";
div.align = "left";
//在 DOM 对象上添加自定义属性,则不会自动让它变成元素的属性
div.mycolor = "red";
alert(div.getAttribute("mycolor")); // null(IE 除外)
//setAttribute()适用于 HTML 属性,也适用于自定义属性
div.setAttribute('myColor','red')
alert(div.getAttribute("mycolor")); // red(IE 除外)
removeAttribute()用于从元素中删除属性。这样不单单是清除属性的值,而是会把整个属性完全从元素中去掉,这个方法用得并不多,但在序列化 DOM 元素时可以通过它控制要包含的属性。
4. attributes 属性
Element 类型是唯一使用 attributes 属性的 DOM 节点类型。attributes 属性包含一个NamedNodeMap 实例,是一个类似 NodeList 的“实时”集合。元素的每个属性都表示为一个 Attr 节点,并保存在这个 NamedNodeMap 对象中。NamedNodeMap 对象包含下列方法:
getNamedItem(name),返回 nodeName 属性等于 name 的节点;
removeNamedItem(name),删除 nodeName 属性等于 name 的节点;(实际上与removeAttribute()这个方法效果一样,实例对象不同)
setNamedItem(node),向列表中添加 node 节点,以其 nodeName 为索引;
item(pos),返回索引位置 pos 处的节点。
一般来说,因为使用起来更简便,通常开发者更喜欢使用 getAttribute()、removeAttribute()和 setAttribute()方法,而不是刚刚介绍的 NamedNodeMap 对象的方法。
attributes 属性最有用的场景是需要迭代元素上所有属性的时候。这时候往往是要把 DOM 结构序列化为 XML 或 HTML 字符串。比如,以下代码能够迭代一个元素上的所有属性并以 attribute1= "value1" attribute2="value2"的形式生成格式化字符串:
//迭代完所有属性后,再将这些名/值对用空格拼接在一起。(这个技术常用于序列化为长字符串。)
function outputAttributes(element) {
let pairs = [];
for (let i = 0, len = element.attributes.length; i < len; ++i) {
const attribute = element.attributes[i];
pairs.push(${attribute.nodeName}="${attribute.nodeValue}"
);
}
return pairs.join(" ");
}
console.log(outputAttributes(div))
//id="myDiv" class="bd" title="Body text" lang="en" dir="ltr"
5. 创建元素
document.createElement()方法创建新元素。这个方法接收一个参数,即要创建元素的标签名,同时也会将其 ownerDocument 属性设置为 document。
let div = document.createElement("div");
div.id = "myNewDiv";
div.className = "box";
console.log(div) //
//此时这个元素还没有添加到文档树,所以不会影响浏览器显示。插入到文档树才会影响显示
document.body.appendChild(div);
//这时候再对这个元素所做的任何修改,都会立即在浏览器中反映出来。
6. 元素后代
元素可以拥有任意多个子元素和后代元素,因为元素本身也可以是其他元素的子元素。childNodes属性包含元素所有的子节点,这些子节点可能是其他元素、文本节点、注释或处理指令。
- Item 1
- Item 2
- Item 3
//在解析以上代码时,
- 元素会包含 7 个子元素,其中 3 个是
- 元素,还有 4 个 Text 节点(表示
- 元素周围的空格)
let a = document.getElementById("myList").childNodes
console.log(a)
for(let i=0; i < a.length;i++){
console.log(a[i].nodeType)
} //text是Node.TEXT_NODE(3),表示li左边的空格
//NodeList(7) [text, li, text, li, text, li, text] //li是HTMLLIElement的实例,包含childNodes下的类型3:text
//3 1 3 1 3 1 3### Text 类型 Text 节点由 Text 类型表示,包含按字面解释的纯文本,也可能包含转义后的 HTML 字符,但不含 HTML 代码。 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 的文本。 默认情况下,包含文本内容的每个元素最多只能有一个文本节点。例如:
Hello World!```
1. 创建文本节点
document.createTextNode()可以用来创建新文本节点,它接收一个参数,即要插入节点的文本。
```
let element = document.createElement("div"); //创建了个div结点
element.className = "message"; //div结点的属性class = "message"
let textNode = document.createTextNode("Hello world!"); //创建了个文字结点,nodeValue=="Hello world!"
element.appendChild(textNode); //文字结点插入div结点
document.body.appendChild(element); //div结点插入dom
```
//一般来说一个元素只包含一个文本子节点。不过,也可以让元素包含多个文本子节点
let anotherTextNode = document.createTextNode("hyh!");
element.appendChild(anotherTextNode);
```
2. 规范化文本节点
DOM 文档中的同胞文本节点可能导致困惑,因为一个文本节点足以表示一个文本字符串。同样,DOM 文档中也经常会出现两个相邻文本节点。
解决方法:normalize(),是在 Node 类型中定义的(因此所有类型的节点上都有这个方法)。在包含两个或多个相邻文本节点的父节点上调用 normalize()时,所有同胞文本节点会被合并为一个文本节点,这个文本节点的 nodeValue 就等于之前所有同胞节点 nodeValue 拼接在一起得到的字符串。
```
let element = document.createElement("div");
element.className = "message";
let textNode = document.createTextNode("Hello world!");
element.appendChild(textNode);
let 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!"
```
浏览器在解析文档时,永远不会创建同胞文本节点。同胞文本节点只会出现在 DOM 脚本生成的文档树中。
3. 拆分文本节点
Text 类型定义了一个与 normalize()相反的方法——splitText()。这个方法可以在指定的偏移位置拆分 nodeValue,将一个文本节点拆分成两个文本节点。
```
let element = document.createElement("div");
element.className = "message";
let textNode = document.createTextNode("Hello world!");
element.appendChild(textNode);
document.body.appendChild(element);
let newNode = element.firstChild.splitText(5);
alert(element.firstChild.nodeValue); // "Hello"
alert(newNode.nodeValue); // " world!" //包括5位置的空格
alert(element.childNodes.length); // 2
```
拆分文本节点最常用于从文本节点中提取数据的 DOM 解析技术。
### Comment 类型
DOM 中的注释通过 Comment 类型表示。Comment 类型的节点具有以下特征:
nodeType 等于 8;
nodeName 值为"#comment";
nodeValue 值为注释的内容;
parentNode 值为 Document 或 Element 对象;不支持子节点。
Comment 类型与 Text 类型继承同一个基类(CharacterData),因此拥有除 splitText()之外Text 节点所有的字符串操作方法。
注释节点可以作为父节点的子节点来访问。比如下面的 HTML 代码:
```
<div id="myDiv"><!-- A comment --></div>
//这里的注释是<div>元素的子节点,这意味着可以像下面这样访问它:
let div = document.getElementById("myDiv");
let comment = div.firstChild;
alert(comment.data); // "A comment"
```
可以使用 document.createComment()方法创建注释节点,参数为注释文本,此外,浏览器不承认结束的标签之后的注释。
### CDATASection 类型
CDATASection 类型表示 XML 中特有的 CDATA 区块。CDATASection 类型继承 Text 类型,因此拥有包括 splitText()在内的所有字符串操作方法。CDATASection 类型的节点具有以下特征:
nodeType 等于 4;
nodeName 值为"#cdata-section";
nodeValue 值为 CDATA 区块的内容;
parentNode 值为 Document 或 Element 对象;不支持子节点。
在真正的 XML 文档中,可以使用 document.createCDataSection()并传入节点内容来创建CDATA 区块。
### DocumentType 类型
DocumentType 类型的节点包含文档的文档类型(doctype)信息,具有以下特征:
nodeType 等于 10;
nodeName 值为文档类型的名称;
nodeValue 值为 null;
parentNode 值为 Document 对象;不支持子节点。
DocumentType 对象在 DOM Level 1 中不支持动态创建,只能在解析文档代码时创建。对于支持这个类型的浏览器,DocumentType 对象保存在 document.doctype 属性中。DOM Level 1 规定了DocumentType 对象的 3 个属性:name、entities 和 notations。其中,name 是文档类型的名称,entities 是这个文档类型描述的实体的 NamedNodeMap,而 notations 是这个文档类型描述的表示法的 NamedNodeMap。因为浏览器中的文档通常是 HTML 或 XHTML 文档类型,所以 entities 和notations 列表为空。(这个对象只包含行内声明的文档类型。)无论如何,只有 name 属性是有用的。这个属性包含文档类型的名称,即紧跟在动态为网页添加脚本:引入外部文件和直接插入源代码。
动态加载外部文件很容易实现,比如下面的