《JavaScript高级程序设计》读书笔记 -14.1 DOM 节点层级


文档对象模型(DOM,Document Object Model)是HTML和XML文档的编程接口。DOM表示由多层节点构成的文档,通过它开发者可以添加、删除和修改页面的各个部分。脱胎于网景和微软早期的动态HTML(DHTML),DOM现在是真正跨平台、语言无关的表示和操作网页的方式。

DOM与浏览器中的HTML 网页相关,并且在JavaScript 中提供了DOM API。

14.1 节点层级

任何HTML或XML文档都可以用DOM表示为一个由节点构成的层级结构。节点分很多类型,每种类型对应着文档中不同的信息和标记,也都有自己不同的特性、数据和方法,而且与其他类型由某种关系。这些关系构成了层级,让标记可以表示为一个以特定节点为根的属性结构。

其中,document 节点表示每个文档的根节点。在这里,根节点的唯一子节点是元素,我们称之为文档元素(documentElement)。文档元素是文档最外层的元素,所有其他元素都存在于这个元素之
内。每个文档只能有一个文档元素。在HTML 页面中,文档元素始终是元素。

HTML 中的每段标记都可以表示为这个树形结构中的一个节点。元素节点表示HTML 元素,属性节点表示属性,文档类型节点表示文档类型,注释节点表示注释。DOM中总共有12 种节点类型,这些类型都继承一种基本类型。

14.1.1 Node类型

在JavaScript中,所有节点类型都继承Node类型,因此所有类型都共享相同的基本属性和方法。

每个节点都有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)

节点类型可通过与这些常量比较来确定,比如:

if (someNode.nodeType == Node.ELEMENT_NODE){
	alert("Node is an element.");
}

浏览器并不支持所有节点类型。开发者最常用到的是元素节点和文本节点。

1 nodeName与nodeValue

nodeName 与nodeValue 保存着有关节点的信息。这两个属性的值完全取决于节点类型。在使用这两个属性前,最好先检测节点类型,如下所示:

if (someNode.nodeType == 1){
	value = someNode.nodeName; // 会显示元素的标签名
}

在这个例子中,先检查了节点是不是元素。如果是,则将其nodeName 的值赋给一个变量。对元素而言,nodeName 始终等于元素的标签名,而nodeValue 则始终为null。

2 节点关系

文档中的所有节点都与其他节点有关系。这些关系可以形容为家族关系,相当于把文档树比作家谱。

每个节点都有一个childNodes 属性,其中包含一个NodeList 的实例。

下面的例子展示了如何使用中括号或使用item()方法访问NodeList 中的元素:

let firstChild = someNode.childNodes[0];
let secondChild = someNode.childNodes.item(1);
let count = someNode.childNodes.length;

使用ES6 的Array.from()静态方法可以把NodeList 对象转换为数组。

let arrayOfNodes = Array.from(someNode.childNodes);

每个节点都有一个parentNode 属性,指向其DOM 树中的父元素。。此外,childNodes 列表中的每个节点都是同一列表中其他节点的同胞节点。而使用previousSibling 和nextSibling 可以在这个列表的节点间导航。

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.");
}

请添加图片描述

最后还有一个所有节点都共享的关系。ownerDocument 属性是一个指向代表整个文档的文档节点的指针。所有节点都被创建它们(或自己所在)的文档所拥有,因为一个节点不可能同时存在于两个或者多个文档中。

3 操纵节点

因为所有关系指针都是只读的,所以DOM 又提供了一些操纵节点的方法。最常用的方法是appendChild(),用于在childNodes 列表末尾添加节点。添加新节点会更新相关的关系指针,包括父节点和之前的最后一个子节点。appendChild()方法返回新添加的节点,如下所示

let returnedNode = someNode.appendChild(newNode);
alert(returnedNode == newNode); // true
alert(someNode.lastChild == newNode); // true

如果想把节点放到childNodes 中的特定位置而不是末尾,则可以使用insertBefore()方法。

// 作为最后一个子节点插入
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()方法接收两个参数:要插入的节点和要替换的节点。要替换的节点会被返回并从文档树中完全移除,要插入的节点会取而代之。

// 替换第一个子节点
let returnedNode = someNode.replaceChild(newNode, someNode.firstChild);
// 替换最后一个子节点
returnedNode = someNode.replaceChild(newNode, someNode.lastChild);

要移除节点而不是替换节点,可以使用removeChild()方法。

// 删除第一个子节点
let formerFirstChild = someNode.removeChild(someNode.firstChild);
// 删除最后一个子节点
let formerLastChild = someNode.removeChild(someNode.lastChild);
4 其他方法

所有节点类型还共享了两个方法。第一个是cloneNode(),会返回与调用它的节点一模一样的节点。cloneNode()方法接收一个布尔值参数,表示是否深复制。在传入true 参数时,会进行深复制,即复制节点及其整个子DOM 树。如果传入false,则只会复制调用该方法的节点。复制返回的节点属于文档所有,但尚未指定父节点,所以可称为孤儿节点(orphan)。可以通过appendChild()、insertBefore()或replaceChild()方法把孤儿节点添加到文档中。

<ul>
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
</ul>
如果myList保存着对这个<ul>元素的引用,则下列代码展示了使用cloneNode()方法的两种方式:
let deepList = myList.cloneNode(true);
alert(deepList.childNodes.length); // 3(IE9 之前的版本)或7(其他浏览器)
let shallowList = myList.cloneNode(false);
alert(shallowList.childNodes.length); // 0

注意 cloneNode()方法不会复制添加到DOM 节点的JavaScript 属性,比如事件处理程序。这个方法只复制HTML 属性,以及可选地复制子节点。

要介绍的最后一个方法是normalize()。这个方法唯一的任务就是处理文档子树中的文本节点。由于解析器实现的差异或DOM 操作等原因,可能会出现并不包含文本的文本节点,或者文本节点之间互为同胞关系。在节点上调用normalize()方法会检测这个节点的所有后代,从中搜索上述两种情形。如果发现空文本节点,则将其删除;如果两个同胞节点是相邻的,则将其合并为一个文本节点。这个方法将在本章后面进一步讨论。

14.1.2 document类型

Document 类型是JavaScript 中表示文档节点的类型。在浏览器中,文档对象document 是HTMLDocument 的实例,表示整个HTML 页面。document 是window对象的属性,因此是一个全局对象。Document类型的节点有以下特征:

子节点可以是DocumentType(最多一个)、Element(最多一个)、ProcessingInstruction或Comment 类型。

1文档子节点

子节点的快捷访问:

  1. documentElement属性,始终指向HTML页面中的<html>元素。
let html = document.documentElement; // 取得对<html>的引用
alert(html === document.childNodes[0]); // true
alert(html === document.firstChild); // true
  1. body 属性,直接指向<body>元素。
let body = document.body; // 取得对<body>的引用

所有主流浏览器都支持document.documentElement 和document.body。

Document 类型另一种可能的子节点是DocumentType。<!doctype>标签是文档中独立的部分,其信息可以通过doctype 属性(在浏览器中是document.doctype)来访问,比如:

let doctype = document.doctype; // 取得对<!doctype>的引用
2文档信息

document 作为HTMLDocument 的实例,还有一些标准Document 对象上所没有的属性。这些属性提供浏览器所加载网页的信息。

其中第一个属性是title,包含<title>元素中的文本,通常显示在浏览器窗口或标签页的标题栏。

// 读取文档标题
let originalTitle = document.title;

// 修改文档标题
document.title = "New page title";

接下来要介绍的3 个属性是URL、domain 和referrer。其中,URL 包含当前页面的完整URL(地址栏中的URL),domain 包含页面的域名,而referrer 包含链接到当前页面的那个页面的URL。如果当前页面没有来源,则referrer 属性包含空字符串。示例 :

// 取得完整的URL
let url = document.URL;
// 取得域名
let domain = document.domain;
// 取得来源
let referrer = document.referrer;

URL 跟域名是相关的。比如,如果document.URL 是http://www.wrox.com/WileyCDA/,则document.domain 就是www.wrox.com。

在这些属性中,只有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"; // 出错!

当页面中包含来自某个不同子域的窗格(<frame>)或内嵌窗格(<iframe>)时,设置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"; // 收紧,错误!
3定位元素

使用DOM 最常见的情形可能就是获取某个或某组元素的引用,然后对它们执行某些操作。document 对象上暴露了一些方法,可以实现这些操作。getElementById()和getElementsByTagName()就是Document 类型提供的两个方法。

getElementById()方法接收一个参数,即要获取元素的ID,如果找到了则返回这个元素,如果没找到则返回null。参数ID 必须跟元素在页面中的id 属性值完全匹配,包括大小写。

<div id="myDiv">Some text</div>

可以使用如下代码取得这个元素:

let div = document.getElementById("myDiv"); // 取得对这个<div>元素的引用

但参数大小写不匹配会返回null:

let div = document.getElementById("mydiv"); // null

如果页面中存在多个具有相同ID 的元素,则getElementById()返回在文档中出现的第一个元素。

getElementsByTagName()是另一个常用来获取元素引用的方法。这个方法接收一个参数,即要获取元素的标签名,返回包含零个或多个元素的NodeList。在HTML 文档中,这个方法返回一个HTMLCollection 对象。

let images = document.getElementsByTagName("img");

取得元素的数量:

alert(images.length); // 图片数量
alert(images[0].src); // 第一张图片的src 属性
alert(images.item(0).src); // 同上

HTMLCollection 对象还有一个额外的方法namedItem(),可通过标签的name 属性取得某一项的引用。如页面中包含<img>元素:

<img src="myimage.gif" name="myImage">

那么也可以像这样从images 中取得对这个元素的引用:

let myImage = images.namedItem("myImage");
let myImage = images["myImage"];

要取得文档中的所有元素,可以传入getElementsByTagName(),

let allElements = document.getElementsByTagName("*");

这行代码可以返回包含页面中所有元素的HTMLCollection 对象,顺序就是它们在页面中出现的顺序。

小结:item是按下标获取,nameItem是按name获取。

HTMLDocument 类型上定义的获取元素的第三个方法是getElementsByName()。方法getElementsByName()最常用于单选按钮,因为同意字段的单选按钮必须具有相同的name属性才能确保把正确的值发送给服务器,比如下面的例子:

<fieldset>
<legend>Which color do you prefer?</legend>
<ul>
<li>
<input type="radio" value="red" name="color" id="colorRed">
<label for="colorRed">Red</label>
</li>
<li>
<input type="radio" value="green" name="color" id="colorGreen">
<label for="colorGreen">Green</label>
</li>
<li>
<input type="radio" value="blue" name="color" id="colorBlue">
<label for="colorBlue">Blue</label>
</li>
</ul>
</fieldset>

下面可以取得所有单选按钮:

let radios = document.getElementsByName("color");

getElementsByName()方法也返回HTMLCollection。不过在这种情况下,namedItem()方法只会取得第一项(因为所有项的name 属性都一样)。

4特殊集合
  • document.anchors 包含文档中所有带name 属性的元素。

  • document.forms 包含文档中所有元素(与document.getElementsByTagName (“form”)
    返回的结果相同)。

  • document.images 包含文档中所有元素(与document.getElementsBy TagName (“img”)
    返回的结果相同)。

  • document.links 包含文档中所有带href 属性的元素。

这些特殊集合始终存在于HTMLDocument 对象上,而且与所有HTMLCollection 对象一样,其内容也会实时更新以符合当前文档的内容。

5DOM 兼容性检测

DOM Level 1 在document.implementation 上只定义了一个方法,即hasFeature()。这个方法接收两个参数:特性名称和DOM版本。

let hasXmlDom = document.implementation.hasFeature("XML", "1.0");

由于实现不一致,因此hasFeature()的返回值并不可靠。目前这个方法已经被废弃,不再建议使用。为了向后兼容,目前主流浏览器仍然支持这个方法,但无论检测什么都一律返回true。

6文档写入

document 对象有一个古老的能力,即向网页输出流中写入内容。这个能力对应4 个方法:write()、writeln()、open()和close()。其中,write()和writeln()方法都接收一个字符串参数,可以将这个字符串写入网页中。write()简单地写入文本,而writeln()还会在字符串末尾追加一个换行符(\n)。这两个方法可以用来在页面加载期间向页面中动态添加内容,如下所示:

<html>
<head>
    <title>document.write() Example</title>
</head>
    <body>
        <p>The current date and time is:
            <script type="text/javascript">
                document.write("<strong>" + (new Date()).toString() + "</strong>")
            </script>
        </p>
    </body>
</html>

write()和writeln()方法经常用于动态包含外部资源,如JavaScript 文件。在包含JavaScript 文件时,记住直接包含字符串"",因为这个字符串会被解释为脚本块的结尾,导致后面的代码不能执行。为避免出现这个问题,需要稍加修改:

<html>
    <head>
        <title>document.write() Example</title>
    </head>
<body>
    <script type="text/javascript">
        document.write("<script type=\"text/javascript\" src=\"file.js\">" +
        "<\/script>");
    </script>
</body>
</html>

前面的例子展示了在页面渲染期间通document.write()向文档中输出内容。如果是在页面加载完之后再调write(),则输出的内容会重写整个页面,document.

<html>
<head>
<title>document.write() Example</title>
</head>
<body>
<p>This is some content that you won't get to see because it will be
overwritten.</p>
<script type="text/javascript">
window.onload = function(){
document.write("Hello world!");
};
</script>
</body>
</html>

这个例子使用了window.onload 事件处理程序,将调用document.write()的函数推迟到页面加载完毕后执行。

open()和close()方法分别用于打开和关闭网页输出流。在调用write()和writeln()时,这两个方法都不是必需的。

14.1.3 Element类型

Element 表示XML或HTML元素,对外暴露出访问元素标签名、子节点和属性的能力。

div.tagName可以获取这个元素的标签名,它实际上返回的是”DIV“而不是“div“。在HTML 中,元素标签名始终以全大写表示;在XML(包括XHTML)中,标签名始终与源代码中的大小写一致。最好将标签名转换为小写形式,以便比较:

if (element.tagName.toLowerCase() == "div"){ // 推荐,适用于所有文档
// 做点什么
}
1 HTML元素

HTMLElement直接继承Element 并增加了一些属性。下面是一些常用的属性:

  • id,元素在文档中的唯一标识符;
  • title,包含元素的额外信息,通常以提示条形式展示;
  • lang,元素内容的语言代码(很少用);
  • dir,语言的书写方向("ltr"表示从左到右,"rtl"表示从右到左,同样很少用);
  • className,相当于class 属性,用于指定元素的CSS 类(因为class 是ECMAScript 关键字,
    所以不能直接用这个名字)。

使用:

<div id="myDiv" class="bd" title="Body text" lang="en" dir="ltr"></div>
//读取
let div = document.getElementById("myDiv");
alert(div.id); // "myDiv"
alert(div.className); // "bd"
alert(div.title); // "Body text"
alert(div.lang); // "en"
alert(div.dir); // "ltr"

//修改
div.id = "someOtherId";
div.className = "ft";
div.title = "Some other text";
div.lang = "fr";
div.dir ="rtl";
2 取得元素

每个元素都有零个或多个属性,通常用于为元素或其内容附加更多信息。与属性相关的DOM 方法主要有3 个:getAttribute()、setAttribute()和removeAttribute()。这些方法主要用于操纵属性,包括在HTMLElement 类型上定义的属性。

let div = document.getElementById("myDiv");
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"

注意,属性名不区分大小写,因此"ID"和"id"被认为是同一个属性。

通过DOM对象访问的属性中有两个返回值根使用getAttribute()取得的值不一样。

  • 第一个属性是style属性。在使用getAttribute()访问style 属性时,返回的是CSS 字符串;而在通过DOM对象的属性访问时,style 属性返回的是一个(CSSStyleDeclaration)对象。

  • 第二个属性其实是一类,即事件处理程序(或者事件属性),比如onclick。在元素上使用事件属性时(比如onclick),属性的值是一段JavaScript 代码。

3 设置属性
div.setAttribute("id", "someOtherId");
div.setAttribute("class", "ft");
div.setAttribute("title", "Some other text");
div.setAttribute("lang","fr");
div.setAttribute("dir", "rtl");

在DOM对象上添加自定义属性,不会自动让它变成元素的属性。

4 attributes属性

Element类型是唯一使用attributes属性的DOM节点类型。

attributes属性最有用的场景是需要迭代元素上所有属性的时候:

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(" ");
}

这个函数使用数组存储每个名/值对,迭代完所有属性后,再将这些名/值对用空格拼接在一起。(这个技术常用于序列化为长字符串。

5 创建元素

可以使document.createElement()方法创建新元素。

let div = document.createElement("div");

添加属性:

div.id = "myNewDiv";
div.className = "box";

添加到文档:

document.body.appendChild(div);
6 元素后代

例子:

<ul id="myList">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul

主要有两种方法:

  1. 以下代码会遍历某个元素的子节点,并且只在nodeType 等于1(即Element 节点)时执行某个
    操作。

    for (let i = 0, len = element.childNodes.length; i < len; ++i) {
        if (element.childNodes[i].nodeType == 1) {
        // 执行某个操作
        }
    }
    
  2. 要取得某个元素的子节点和其他后代节点,可以使用元素的getElementsByTagName()方法。

    let ul = document.getElementById("myList");
    let items = ul.getElementsByTagName("li");
    
14.1.4 Text类型

Text 节点中包含的文本可以通过nodeValue 属性访问,也可以通过data 属性访问,这两个属性包含相同的值。

方法有:

  • 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 属性获取文本节点中包含的字符数量。

默认情况下,包含文本内容的每个元素最多只能有一个文本节点。

<!-- 没有内容,因此没有文本节点 -->
<div></div>
<!-- 有空格,因此有一个文本节点 -->
<div> </div>
<!-- 有内容,因此有一个文本节点 -->
<div>Hello World!</div>

修改文本节点会被转换成实体编码:

// 输出为"Some &lt;strong&gt;other&lt;/strong&gt; message"
div.firstChild.nodeValue = "Some <strong>other</strong> message";
1 创建文本节点

document.createTextNode()可以用来创建新文本节点,它接收一个参数,即要插入节点的文本。

let element = document.createElement("div");
element.className = "message";
let textNode = document.createTextNode("Hello world!");
element.appendChild(textNode);
document.body.appendChild(element);

这个例子首先创建了一个

元素并给它添加了值为"message"的class 属性,然后又创建了一个文本节点并添加到该元素。最后一步是把这个元素添加到文档的主体上,这样元素及其包含的文本会出现在浏览器中。

一般来说一个元素只包含一个文本子节点。不过,也可以让元素包含多个文本子节点,如下面的例子所示:

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);

在将一个文本节点作为另一个文本节点的同胞插入后,两个文本节点的文本之间不会包含空格。

2 规范化文本节点

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!"
alert(element.childNodes.length); // 2

拆分文本节点最常用于从文本节点中提取数据的DOM解析技术。

14.1.5 Comment类型

Comment 类型与Text 类型继承同一个基类(CharacterData),因此拥有除splitText()之外Text 节点所有的字符串操作方法。与Text 类型相似,注释的实际内容可以通过nodeValue 或data属性获得。

注释节点可以作为父节点的子节点来访问。

<div id="myDiv"><!-- A comment --></div>

这里的注释是

元素的子节点,这意味着可以像下面这样访问它:

let div = document.getElementById("myDiv");
let comment = div.firstChild;
alert(comment.data); // "A comment"

可以使用document.createComment()方法创建注释节点,参数为注释文本。

14.1.6 CDATASection类型

CDATASection类型表示XML中特有的CDATA区块。

CDATA区块在XML文档中有效。

14.1.7 DocumentType类型

DocumentType 对象保存在document.doctype 属性中。DOM Level 1 规定了DocumentType 对象的3 个属性:name、entities 和notations。

<!DOCTYPE HTML PUBLIC "-// W3C// DTD HTML 4.01// EN"
"http:// www.w3.org/TR/html4/strict.dtd">

对于这个文档类型,name 属性的值是"html":

alert(document.doctype.name); // "html
14.1.8 DocumentFragment类型

在所有节点类型中,DocumentFragment 类型是唯一一个在标记中没有对应表示的类型。DOM将文档片段定义为“轻量级”文档,能够包含和操作节点,却没有完整文档那样额外的消耗。

可以使用document.createDocumentFragment()方法像下面这样创建文档片段:

let fragment = document.createDocumentFragment();

下面的HTML为例:

<ul id="myList"></ul>

假设想给这个

  • 元素添加3 个列表项。如果分3 次给这个元素添加列表项,浏览器就要重新渲染3 次页面,以反映新添加的内容。为避免多次渲染,下面的代码示例使用文档片段创建了所有列表项,然后一次性将它们添加到了
    • 元素:

let fragment = document.createDocumentFragment();
let ul = document.getElementById("myList");

for (let i = 0; i < 3; ++i) {
    let li = document.createElement("li");
    li.appendChild(document.createTextNode(`Item ${i + 1}`));
	fragment.appendChild(li);
}

ul.appendChild(fragment);

这个例子先创建了一个文档片段,然后取得了

  • 元素的引用。接着通过for 循环创建了3 个列表项,每一项都包含表明自己身份的文本。为此先创建
  • 元素,再创建文本节点并添加到该元素。然后通过appendChild()把
  • 元素添加到文档片段。循环结束后,通过把文档片段传给appendChild()将所有列表项添加到了
    • 元素。此时,文档片段的子节点全部被转移到了
      • 元素。

14.1.9 Attr类型

元素数据在DOM中通过Attr类型表示。Attr类型构造函数嗯哼原型在素有浏览器中都可以直接访问。

开发者更喜欢使用getAttribute()、removeAttribute()和setAttribute()方法操作属性。

Attr 对象上有3 个属性:name、value 和specified。其中,name 包含属性名(与nodeName一样),value 包含属性值(与nodeValue 一样),而specified 是一个布尔值,表示属性使用的是默认值还是被指定的值。

比如,要给元素添加align 属性,可以使用下列代码:

let attr = document.createAttribute("align");
attr.value = "left";
element.setAttributeNode(attr);
alert(element.attributes["align"].value); // "left"
alert(element.getAttributeNode("align").value); // "left"
alert(element.getAttribute("align")); // "left"
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值