DOM编程之API学习总结篇
原文 链接
# 一、基本类型介绍
# 1.1 Node类型
DOM1级定义了一个Node接口,该接口由DOM中所有节点类型实现。这个Node接口在JS中是作为Node类型实现的。在IE9以下版本无法访问到这个类型,JS中所有节点都继承自Node类型,都共享着相同的基本属性和方法Node有一个属性nodeType表示Node的类型,它是一个整数,其数值分别表示相应的Node类型


- 假设我们要判断一个
Node是不是元素,我们可以这样判断
if(someNode.nodeType == 1){
console.log("Node is a element");
}
@前端进阶之旅: 代码已经复制到剪贴板
- 这些
Node类型中,我们最常用的就是element,text,attribute,comment,document,document_fragment这几种类型
# 1.2 Element类型

-
Element提供了对元素标签名,子节点和特性的访问,我们常用HTML元素比如div,span,a等标签就是element中的一种。 -
Element有下面几条特性:nodeType为1nodeName为元素标签名,tagName也是返回标签名nodeValue为nullparentNode可能是Document或Element- 子节点可能是
Element,Text,Comment,Processing_Instruction,CDATASection或EntityReference
# 1.3 Text类型

Text表示文本节点,它包含的是纯文本内容,不能包含html代码,但可以包含转义后的html代码。Text有下面的特性:nodeType为3nodeName为#textnodeValue为文本内容parentNode是一个Element- 没有子节点
# 1.4 Attr类型

Attr类型表示元素的特性,相当于元素的attributes属性中的节点,它有下面的特性:nodeType值为2nodeName是特性的名称nodeValue是特性的值parentNode为null
# 1.5 Comment类型
Comment表示HTML文档中的注释,它有下面的几种特征:nodeType为8nodeName为#commentnodeValue为注释的内容parentNode可能是Document或Element- 没有子节点
# 1.6 Document

Document表示文档,在浏览器中,document对象是HTMLDocument的一个实例,表示整个页面,它同时也是window对象的一个属性。Document有下面的特性:nodeType为9nodeName为#documentnodeValue为nullparentNode为null- 子节点可能是一个
DocumentType或Element
# 1.7 DocumentFragment类型
-
DocumentFragment是所有节点中唯一一个没有对应标记的类型,它表示一种轻量级的文档,可能当作一个临时的仓库用来保存可能会添加到文档中的节点。DocumentFragment有下面的特性:nodeType为11nodeName为#document-fragmentnodeValue为nullparentNode为null
-
我们简单地介绍了几种常见的
Node类型,要记住,HTML中的节点并不只是包括元素节点,它还包括文本节点,注释节点等等。在这里我们只是简单地说明了几种常见的节点.
# 二、 DOM提供的几个属性
# 2.1 childNodes属性
- 在一棵节点树上,
childNodes属性可以用来获取任何一个元素的所有子节点,它是一个包含这个元素全部子元素的数组
element.childNodes
@前端进阶之旅: 代码已经复制到剪贴板
# 2.2 nodeType属性
- 节点之间的关系构成了节点层次,
html页面的可以画出一个以html标签为根节点的树形结构DOM会把文档看作是一棵树,同时定义了很多方法来操作这棵数中的每一个元素(节点)
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<p>hello world!!!</p>
</body>
</html>
@前端进阶之旅: 代码已经复制到剪贴板

- 每一个节点都有
nodeType属性
node.nodeType
@前端进阶之旅: 代码已经复制到剪贴板
nodeType属性总共有12中可能取值,但其中仅有3种有实用价值- 元素节点的
nodeType属性值是1 - 属性节点的
nodeType属性值是2 - 文本节点的
nodeType属性值是3
- 元素节点的
description.firstChild.nodeValue = text;
@前端进阶之旅: 代码已经复制到剪贴板
# 2.3 nodeValue属性
nodeValue属性- 如果想改变一个文本节点的值,那就使用
DOM提供的nodeValue,它用来得到一个节点的值node.nodeValue - 需要注意:
nodeValue属性获取对象的值时,得到的并不是包含在这个段落里的文本 - nodeValue属性不仅可以用来检测节点的值,还可以设置节点的值
- 如果想改变一个文本节点的值,那就使用
# 2.4 firstChild和lastChild属性
- 数组元素
childNodes[0]有个更直观的同义词。无论如何,只要访问childNodes数组的第一个元素,都可以把它写成firstChild
node.firstChild
@前端进阶之旅: 代码已经复制到剪贴板
与下面等价
node.childNodes[0]
@前端进阶之旅: 代码已经复制到剪贴板
DOM还提供了一个与之对应的lastChild属性
node.lastChild
@前端进阶之旅: 代码已经复制到剪贴板
# 三、节点创建型API
- 在这里,我将常用的
DOM操作api进行分类,首先要介绍的是创建型的api。这一类型的api,简而言之就是用来创建节点的
# 3.1 createElement
createElement通过传入指定的一个标签名来创建一个元素,如果传入的标签名是一个未知的,则会创建一个自定义的标签,注意:IE8以下浏览器不支持自定义标签
var div = document.createElement("div");
@前端进阶之旅: 代码已经复制到剪贴板
- 使用
createElement要注意:通过createElement创建的元素并不属于html文档,它只是创建出来,并未添加到html文档中,要调用appendChild或insertBefore等方法将其添加到HTML文档树中
# 3.2 createTextNode
createTextNode用来创建一个文本节点,用法如下
var textNode = document.createTextNode("一个TextNode");
@前端进阶之旅: 代码已经复制到剪贴板
createTextNode接收一个参数,这个参数就是文本节点中的文本,和createElement一样,创建后的文本节点也只是独立的一个节点,同样需要appendChild将其添加到HTML文档树中
# 3.3 cloneNode
cloneNode是用来返回调用方法的节点的一个副本,它接收一个bool参数,用来表示是否复制子元素,使用如下:
var parent = document.getElementById("parentElement");
var parent2 = parent.cloneNode(true);// 传入true
parent2.id = "parent2";
@前端进阶之旅: 代码已经复制到剪贴板
- 这段代码通过
cloneNode复制了一份parent元素,其中cloneNode的参数为true,表示parent的子节点也被复制,如果传入false,则表示只复制了parent节点
<div id="parent">
我是父元素的文本
<br/>
<span>
我是子元素
</span>
</div>
<button id="btnCopy">复制</button>
var parent = document.getElementById("parent");
document.getElementById("btnCopy").onclick = function(){
var parent2 = parent.cloneNode(true);
parent2.id = "parent2";
document.body.appendChild(parent2);
}
@前端进阶之旅: 代码已经复制到剪贴板
-
这段代码很简单,主要是绑定
button事件,事件内容是复制了一个parent,修改其id,然后添加到文档中 -
这里有几点要注意:
- 和
createElement一样,cloneNode创建的节点只是游离有html文档外的节点,要调用appendChild方法才能添加到文档树中 - 如果复制的元素有
id,则其副本同样会包含该id,由于id具有唯一性,所以在复制节点后必须要修改其id - 调用接收的
bool参数最好传入,如果不传入该参数,不同浏览器对其默认值的处理可能不同
- 和
-
除此之外,我们还有一个需要注意的点:
- 如果被复制的节点绑定了事件,则副本也会跟着绑定该事件吗?这里要分情况讨论:
- 如果是通过
addEventListener或者比如onclick进行绑定事件,则副本节点不会绑定该事件 - 如果是内联方式绑定比如
- 如果是通过
- 如果被复制的节点绑定了事件,则副本也会跟着绑定该事件吗?这里要分情况讨论:
<div onclick="showParent()"></div>
@前端进阶之旅: 代码已经复制到剪贴板
- 这样的话,副本节点同样会触发事件
# 3.4 createDocumentFragment
-
createDocumentFragment方法用来创建一个DocumentFragment。在前面我们说到DocumentFragment表示一种轻量级的文档,它的作用主要是存储临时的节点用来准备添加到文档中 -
createDocumentFragment方法主要是用于添加大量节点到文档中时会使用到。假设要循环一组数据,然后创建多个节点添加到文档中
<ul id="list"></ul>
<input type="button" value="添加多项" id="btnAdd" />
document.getElementById("btnAdd").onclick = function(){
var list = document.getElementById("list");
for(var i = 0;i < 100; i++){
var li = document.createElement("li");
li.textContent = i;
list.appendChild(li);
}
}
@前端进阶之旅: 代码已经复制到剪贴板
-
这段代码将按钮绑定了一个事件,这个事件创建了100个
li节点,然后依次将其添加HTML文档中。这样做有一个缺点:每次一创建一个新的元素,然后添加到文档树中,这个过程会造成浏览器的回流。所谓回流简单说就是指元素大小和位置会被重新计算,如果添加的元素太多,会造成性能问题。这个时候,就是使用createDocumentFragment了 -
DocumentFragment不是文档树的一部分,它是保存在内存中的,所以不会造成回流问题。我们修改上面的代码如下
- 优化后的代码主要是创建了一个
fragment,每次生成的li节点先添加到fragment,最后一次性添加到list
# 3.5 创建型API总结
# 四、页面修改型API
# 4.1 appendChild
appendChild我们在前面已经用到多次,就是将指定的节点添加到调用该方法的节点的子元素的末尾。调用方法如下:
parent.appendChild(child);
@前端进阶之旅: 代码已经复制到剪贴板



