原生DOM入门

原生DOM接口挺多的,须要花点时间研究下,不过先把基础整好,后面框架估计好学点。javascript

1. DOM是啥

1.1 知识回顾

先回顾一下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

Js基本语法的对应

页面中的节点,根据Element、Text、Document、Comment这些构造函数,构造出对象来,内存就理解了。app

好比构造div框架

var div = document.createElement('div')
undefined
div 
<div></div> //打印结果
复制代码

createElement就是构造函数。

把DOM的对应和JS基本语法练习起来。

1.2 DOM的真面目

前面的基础分析完了,就能够知道什么是DOM了。

完整的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接口学习。


2. 原生DOM API

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

2.1 Node的属性

DOM树的最小单位就是节点(node)。文档的树形结构就是有各个不一样列类型的节点组成的,每一个节点均可以看作是这棵DOM树的叶子

常见的七种node类型

名字 做用
Document 整个文档树的顶层节点 但不是根节点
DocumentType doctype标签
Element 网页的其余各类标签
Attribute 标签的属性
Text 标签与标签之间的文本
Comment 注释
DocumentFragment 文档的片断

咱们只关心Document、Element、Text

2.1.1 node之间的关系属性

  1. 一个最顶层的节点 document,表明整个文档。
  2. 一个根节点 html,是文档里面最高的一层,是根节点。其余全部的html标签都是他的下级
  3. 其余节点与周围节点的关系
    1. parentNode: 直接的那个上级的节点
    2. childNodes: 直接的下一级的节点
    3. sibling:拥有同一个父节点的节点
Node.childNodes

返回一个NodeList集合,成员包括当前节点的全部子节点。注意,除了HTML元素节点,该属性返回的还包括Text节点和Comment节点。若是当前节点不包括任何子节点,则返回一个空的NodeList集合。因为NodeList对象是一个动态集合,一旦子节点发生变化,马上会反映在返回结果之中。

  • childNodes

注意: childNodes会把text也打印出来,也就是两个标签之间的换行符。

文本节点

并且childNodes返回一个伪数组。这个伪数组对象的每个元素依然都是html元素,若是想操做元素的内容还要用元素的其余属性。

  • document的childNodes只有两个
document.childNodes
(2) [<!DOCTYPE html>, html] 0:<!DOCTYPE html> 1:html length:2 __proto__: NodeList 复制代码
  • 因此咱们不想打印出text节点,可使用children属性啊
ParentNode.children //ParentNode要是一个HTMLCollection
复制代码

上述children属性会返回 一个Node的子elements 而没有text节点。

Node.firstChild和Node.lastChild

firstChild属性返回当前节点的第一个子节点,若是当前节点没有子节点,则返回null(注意,不是undefined)。

Node.lastChild属性返回当前节点的最后一个子节点,若是当前节点没有子节点,则返回null。

Node.nextSibling和Node.previousSibling

Node.nextSibling属性返回紧跟在当前节点后面的第一个同级节点。若是当前节点后面没有同级节点,则返回null

previousSibling属性返回当前节点前面的、距离最近的一个同级节点。若是当前节点前面没有同级节点,则返回null

以上的三组属性使用时必定要注意结果会有text的影响。

Node.parentNode
document.parentNode
null
复制代码

parentNode属性返回当前节点的父节点。对于一个节点来讲,它的父节点只多是三种类型:element节点、document节点和documentfragment节点。

并且document节点和documentfragment节点,它们的父节点都是null。另外,对于那些生成后还没插入DOM树的节点,父节点也是null。

Node.parentElement

parentElement属性返回当前节点的父Element节点。若是当前节点没有父节点,或者父节点类型不是Element节点,则返回null。

注意: 在IE浏览器中,只有Element节点才有该属性,其余浏览器则是全部类型的节点都有该属性。

ownerDocument属性返回当前节点所在的顶层文档对象,即document对象


2.1.2 node自身的属性

nodeName和nodeType

nodeName返回node的名字,若是是element那名字是大写的,其余的名字前面写上#。nodeType返回node的类型,通常用数字表示,1表示element(也能够用Node.ELEMENT_NODE来表示),3表示text(Node.TEXT_NODE)。

  • 若是是element,那么nodeName === tagName
  • 若是是text,那么nodeName = #text, tagName = undefined

nodeName和tagName

关于nodeType有个详细的表格,应该查看MDN记住。对照表

nodeValue

nodeValue属性返回或设置当前节点的值。对于text, comment节点来讲, nodeValue返回该节点的文本内容,对于 attribute 节点来讲, 返回该属性的属性值,而对于document和element节点来讲,返回null。 貌似没个卵用,最多见的element都是null,仍是用下面的textContent

textContent和innerText之争

火狐推出的textContent,得到一个节点及其后代的文本内容,通常用这个得到元素的内容。

IE推出的innerText,二者有很大的区别。

关于textContent、innerText、innnerHTML之间的区别请看MDN


2.2 Node的方法

Node.appendChild()

Node.appendChild() 方法将一个节点添加到指定父节点的子节点列表的末尾

var child = node.appendChild(child);

  • node 是要插入子节点的父节点.
  • child便是参数又是这个方法的返回值.

div添加空的p元素

打印出p那个元素

Node.cloneNode()

这个方法就是克隆一个node,分为浅拷贝和深拷贝。

  • 浅拷贝,Node.cloneNode()只克隆元素节点自己,而不会克隆它的子节点。包括它的文本节点
  • 深拷贝,Node.cloneNode(true)克隆元素的全部属性以及子节点

注意:为了防止一个文档中出现两个ID重复的元素,使用cloneNode()方法克隆的节点在须要时应该指定另一个与原ID值不一样的ID

若是你想克隆同一个id的元素到不一样的元素后面,会报错。

Node.contains()

判断一个节点是否是另外一个节点的子节点。

div.contains(div1)
复制代码

div1是div的子节点就返回true。

Node.hasChildNodes()
div.hasChildNodes()
复制代码

判断div节点是否还有子节点,有子节点就返回true。

Node.insertBefore()

在当前节点的某个子节点以前再插入一个子节点。

var insertedElement = parentElement.insertBefore(newElement, referenceElement);
复制代码

在parentElement节点的子节点referenceElement前面插入一个newElement节点。

若是referenceElementnullnewElement将被插入到子节点的末尾*。*若是newElement已经在DOM树中,newElement首先会从DOM树中移除。

没有 insertAfter 方法。可使用 insertBefore 方法和 nextSibling 来模拟它。

parentDiv.insertBefore(sp1, sp2.nextSibling);
复制代码

只要sp2.nextSibling === null,那么就能够在parentDiv的末尾添加sp1元素。

Node.isEqualNode()和Node.isSameNode()

二者都是比较两个node是否相等。不过isEqualNode()是两个node看起来相等就返回true,isSameNode()严格使用===判断,并且该方法已被废弃,若是要严格判断两个node是否指向同一个对象,直接用node1 === node2。

Node.normalize()

就是规范化的意思。什么是规范化,在一个"规范化"后的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()和Node.replaceChild()

Node.removeChild()是从当前节点删除一个子节点,不过内存里面依然存在,只不过不在页面显示了,返回的就是被移除的那个节点。因此说一个节点移除之后,依然可使用它,好比插入到另外一个节点下面。

未移除子元素的时候

移除以后

以上是我作的demo

Node.replaceChild方法用于将一个新的节点,替换掉当前节点的一个子节点。它接受两个参数,第一个参数是用来替换的新节点,第二个参数将要被替换走的子节点。它返回被替换走的那个节点。

未替换

替换了

我作的实验demo

Document属性和方法

关于Document接口的属性和方法,且听下回分解~

相关文章
相关标签/搜索