原生DOM接口挺多的,须要花点时间研究下,不过先把基础整好,后面框架估计好学点。javascript
先回顾一下HTML的基本结构html
<!DOCTYPE html>
<html lang="zh-Hans">
<head>
</head>
<body>
</body>
</html>
复制代码
以上就是最简单的HTML 5的结构。通常咱们会把它处理成一棵树,一棵节点树。java
以上就是一棵树,浏览器把html渲染成的树,也就是Document结构。每一个框就是一个Element、标题等文本内容是Text。node
Document、Element、Text 的祖先都是Node。 如下是MDN的继承树编程
但是在内存中,存的不是html树,是一棵对应html各个节点的对象树,并且对象树的节点是与html树的节点一一对应的。数组
以上是内存中的对象树。这些对象应该怎么定义,是由DOM规范规定的。浏览器
也能够以下这么理解bash
页面中的节点,根据Element、Text、Document、Comment这些构造函数,构造出对象来,内存就理解了。app
好比构造div框架
var div = document.createElement('div')
undefined
div
<div></div> //打印结果
复制代码
createElement
就是构造函数。
把DOM的对应和JS基本语法练习起来。
前面的基础分析完了,就能够知道什么是DOM了。
DOM就是完整的把Document和Object映射到一块儿,符合DOM规范的结构,因此具有不少的API。
DOM 是 JavaScript 操做网页的接口,全称为“文档对象模型”(Document Object Model)。它的做用是将网页转为一个 JavaScript 对象,从而能够用脚本进行各类操做(好比增删内容)。
浏览器会根据 DOM 模型,将结构化文档(好比 HTML 和 XML)解析成一系列的节点,再由这些节点组成一个树状结构(DOM Tree)。全部的节点和最终的树状结构,都有规范的对外接口。因此,DOM 能够理解成网页的编程接口。DOM 有本身的国际标准,目前的通用版本是DOM 3,下一代版本DOM 4正在拟定中。
严格地说,DOM 不属于 JavaScript,可是操做 DOM 是 JavaScript 最多见的任务,而 JavaScript 也是最经常使用于 DOM 操做的语言。
规范里的DOM模型居然有多达31个接口,我先只挑Node接口和Document接口学习。
DOM是一棵树,树上有Node,Node分为Document、Element、Text,其余的能够忽略。
由前面的继承图可知Node的研究价值很高,咱们先来看Node接口的属性和方法。 下面是MDN对Node接口的解释
Node是一个接口,许多DOM类型从这个接口继承,并容许相似地处理(或测试)这些各类类型。
- 如下接口都从Node继承其方法和属性: Document, Element, CharacterData (which Text, Comment, and CDATASection inherit), ProcessingInstruction, DocumentFragment, DocumentType, Notation, Entity, EntityReference
DOM树的最小单位就是节点(node)。文档的树形结构就是有各个不一样列类型的节点组成的,每一个节点均可以看作是这棵DOM树的叶子
常见的七种node类型
名字 | 做用 |
---|---|
Document | 整个文档树的顶层节点 但不是根节点 |
DocumentType | doctype标签 |
Element | 网页的其余各类标签 |
Attribute | 标签的属性 |
Text | 标签与标签之间的文本 |
Comment | 注释 |
DocumentFragment | 文档的片断 |
咱们只关心Document、Element、Text
返回一个NodeList集合,成员包括当前节点的全部子节点。注意,除了HTML元素节点,该属性返回的还包括Text节点和Comment节点。若是当前节点不包括任何子节点,则返回一个空的NodeList集合。因为NodeList对象是一个动态集合,一旦子节点发生变化,马上会反映在返回结果之中。
注意: childNodes会把text也打印出来,也就是两个标签之间的换行符。
并且childNodes返回一个伪数组。这个伪数组对象的每个元素依然都是html元素,若是想操做元素的内容还要用元素的其余属性。
document.childNodes
(2) [<!DOCTYPE html>, html] 0:<!DOCTYPE html> 1:html length:2 __proto__: NodeList 复制代码
children
属性啊ParentNode.children //ParentNode要是一个HTMLCollection
复制代码
上述children属性会返回 一个Node的子elements 而没有text节点。
firstChild
属性返回当前节点的第一个子节点,若是当前节点没有子节点,则返回null
(注意,不是undefined
)。
Node.lastChild
属性返回当前节点的最后一个子节点,若是当前节点没有子节点,则返回null。
Node.nextSibling
属性返回紧跟在当前节点后面的第一个同级节点。若是当前节点后面没有同级节点,则返回null
。
previousSibling
属性返回当前节点前面的、距离最近的一个同级节点。若是当前节点前面没有同级节点,则返回null
。
以上的三组属性使用时必定要注意结果会有text的影响。
document.parentNode
null
复制代码
parentNode
属性返回当前节点的父节点。对于一个节点来讲,它的父节点只多是三种类型:element
节点、document
节点和documentfragment
节点。
并且document节点和documentfragment节点,它们的父节点都是null。另外,对于那些生成后还没插入DOM树的节点,父节点也是null。
parentElement属性返回当前节点的父Element节点。若是当前节点没有父节点,或者父节点类型不是Element节点,则返回null。
注意: 在IE浏览器中,只有Element节点才有该属性,其余浏览器则是全部类型的节点都有该属性。
ownerDocument
属性返回当前节点所在的顶层文档对象,即document
对象
nodeName返回node的名字,若是是element那名字是大写的,其余的名字前面写上#。nodeType返回node的类型,通常用数字表示,1表示element(也能够用Node.ELEMENT_NODE来表示),3表示text(Node.TEXT_NODE)。
关于nodeType有个详细的表格,应该查看MDN记住。对照表
nodeValue属性返回或设置当前节点的值。对于text, comment节点来讲, nodeValue
返回该节点的文本内容,对于 attribute 节点来讲, 返回该属性的属性值,而对于document和element节点来讲,返回null。 貌似没个卵用,最多见的element都是null,仍是用下面的textContent
吧
火狐推出的textContent,得到一个节点及其后代的文本内容,通常用这个得到元素的内容。
IE推出的innerText,二者有很大的区别。
关于textContent、innerText、innnerHTML之间的区别请看MDN
Node.appendChild()
方法将一个节点添加到指定父节点的子节点列表的末尾。
var child = node.appendChild(child);
node
是要插入子节点的父节点.child
便是参数又是这个方法的返回值.这个方法就是克隆一个node,分为浅拷贝和深拷贝。
Node.cloneNode()
只克隆元素节点自己,而不会克隆它的子节点。包括它的文本节点Node.cloneNode(true)
克隆元素的全部属性以及子节点注意:为了防止一个文档中出现两个ID重复的元素,使用cloneNode()方法克隆的节点在须要时应该指定另一个与原ID值不一样的ID
判断一个节点是否是另外一个节点的子节点。
div.contains(div1)
复制代码
div1是div的子节点就返回true。
div.hasChildNodes()
复制代码
判断div节点是否还有子节点,有子节点就返回true。
在当前节点的某个子节点以前再插入一个子节点。
var insertedElement = parentElement.insertBefore(newElement, referenceElement);
复制代码
在parentElement节点的子节点referenceElement前面插入一个newElement节点。
若是referenceElement
为null
则newElement
将被插入到子节点的末尾*。*若是newElement
已经在DOM树中,newElement
首先会从DOM树中移除。
没有 insertAfter
方法。可使用 insertBefore
方法和 nextSibling
来模拟它。
parentDiv.insertBefore(sp1, sp2.nextSibling);
复制代码
只要sp2.nextSibling === null,那么就能够在parentDiv的末尾添加sp1元素。
二者都是比较两个node是否相等。不过isEqualNode()是两个node看起来相等就返回true,isSameNode()严格使用===判断,并且该方法已被废弃,若是要严格判断两个node是否指向同一个对象,直接用node1 === node2。
就是规范化的意思。什么是规范化,在一个"规范化"后的DOM树中,不存在一个空的文本节点,或者两个相邻的文本节点。
var wrapper = document.createElement("div");
wrapper.appendChild(document.createTextNode("Part 1 "));
wrapper.appendChild(document.createTextNode("Part 2 "));
// 这时(规范化以前),wrapper.childNodes.length === 2
// wrapper.childNodes[0].textContent === "Part 1 "
// wrapper.childNodes[1].textContent === "Part 2 "
wrapper.normalize();
// 如今(规范化以后), wrapper.childNodes.length === 1
// wrapper.childNodes[0].textContent === "Part 1 Part 2"
复制代码
以上是MDN的例子,很好懂。
以上是本身模仿的demo
Node.removeChild()是从当前节点删除一个子节点,不过内存里面依然存在,只不过不在页面显示了,返回的就是被移除的那个节点。因此说一个节点移除之后,依然可使用它,好比插入到另外一个节点下面。
以上是我作的demo
Node.replaceChild
方法用于将一个新的节点,替换掉当前节点的一个子节点。它接受两个参数,第一个参数是用来替换的新节点,第二个参数将要被替换走的子节点。它返回被替换走的那个节点。
我作的实验demo
关于Document接口的属性和方法,且听下回分解~