1.背景介绍
DOM是“ Document Object Model ”的缩写,简称“ 文档对象模型 ”

在浏览器中当前载入的文档用文档对象模型来表示。这是一个由浏览器生成的“树结构”,使编程语言可以很容易的访问HTML结构 — 例如浏览器自己在呈现页面时,使用它将样式和其他信息应用于正确的元素,而页面呈现完成以后,可以用JavaScript操作DOM,重构整个 HTML 文档,添加、移除、改变或重排页面上的内容(CRUD - 增删改查)。

全局变量document对象就是整个DOM树的根节点。文档中每个元素和文本在树中都有它们自己的入口 — 称之为节点Node。

2.知识剖析
DOM 操作CRUD - 增删改查
Create:动态增加DOM 节点

Delete:删除DOM 节点

Update:更新DOM 节点的内容

Read:获取DOM 节点

获取DOM
1 Document.getElementById()

2 Document.getElementsByTagName()

3 Document.getElementsByClassName()

4 Document.querySelector()

5 Document.querySelectorAll()

6 父节点Node.parentNode

7 子节点Node.children || Node.childNodes

getElementById( ) 返回一个节点对象

getElementsByTagName( )  getElementsByClassName() 将返回得到的元素节点数组;

getElementById( ) 是 document (根节点)的一个方法,其他元素节点不能使用该方法。因为 id 属性在整个HTML文档中是唯一的,因此必须从根节点开始寻找。 

getElementsByTagName() 是所有元素节点的方法,不仅 document(根节点)可以使用,其他节点也可以使用。所以,根据HTML标签名称来获取DOM节点不仅可以从 document(根节点)开始寻找,还可以从任何其他元素节点开始寻找。

Document.querySelector()是推荐的主流方法,它允许你使用CSS选择器选择元素,匹配在文档中第一个元素。

Document.querySelectorAll(),匹配文档中每个匹配选择器的元素,并把它们的引用存储在一个array中。

获取已知节点的父节点使用 parentNode 。

children 获取所有子节点。 children只返回HTML节点,甚至不返回文本节点,虽然不是标准的DOM属性,但是得到了几乎所有浏览器的支持。

在W3C规范中,是通过 childNodes 来获取子节点的,它是一个标准属性,返回指定元素的子节点的集合,包括HTML节点、文本节点、注释节点等,比 children 返回的节点类型更加广泛。

ele.children || ele.childNodes
firstChild 来获取第一个子节点。lastChild 来获取最后一个子节点。

通过 hasChildNodes() 方法来判断是否存在子节点。

previousSibling 来获取上一个节点。nextSibling 来获取下一个节点。


节点类型nodeType    节点名称nodeName    节点值nodeValue
元素节点    HTML标签的名称(大写)    1
属性节点    属性的名称    2
文本节点    元素节点或属性节点中的文本内容;值永远是#text    3
注释节点    文档注释,形式为<!-- comment text -->    8
文档节点    DOM 树的根节点;值永远是#document    9

DOM节点信息包括节点类型(nodeType)、节点名称(nodeName)和节点值(nodeValue)。
获取元素节点,可以通过 nodeType 属性来进行刷选,nodeType==1 的节点为元素节点。

更新DOM
1 修改节点的文本

innerHTML属性 
不但可以修改一个DOM节点的文本内容,还可以直接通过HTML片段修改DOM节点内部的子树

innerText或textContent属性

2 修改节点的css

Node.style.cssProperty 
获取的是DOM节点上 style 属性定义的样式即行内样式,‘—’在JavaScript中无效,所以需要在JavaScript中改写为驼峰式命名

Node.setAttribute() 

像上面一样直接设置行内样式;预定义样式,设置相应的类名,实现css、js 的分离,不生成行内样式。

增加DOM
1 创建节点

方法    说明
createElement()    元素节点
createTextNode()    文本节点
createComment()    文本节点
createDocumentFragment()    文档碎片节点
createDocumentFragment() 用来创建文档碎片节点。

文档碎片节点是若干DOM节点的集合,可以包括各种类型的节点,如 元素节点、文本节点、注释节点 等。文档碎片节点在创建之初是空的,需要向它添加节点。
每一次DOM节点的添加、删除和移动操作都会引起浏览器重新渲染HTML文档,如果这样的操作过多,不仅会浪费资源,可能还会出现“闪屏” 的现象。 为了减轻浏览器的负担,提高用户体验,最好将所有节点一次添加到DOM(HTML文档),文档碎片节点就派上了用场,可以先将所有节点添加到文档碎片节点,再将文档碎片节点添加到DOM(HTML文档)。
2 添加节点
innerHTML 

空DOM节点插入新的DOM节点,非空DOM节点会直接替换掉原来的所有子节点 

appendChild() Node.appendChild() 

把一个子节点添加到父节点的最后一个子节点;如果节点已经存在于当前文档树,这个节点会从原先的位置删除,再插入到新的位置。 

insertBefore() parentNode.insertBefore(newNode , thisNode) 

在指定节点的前面插入新节点,重点是要获取参考节点 

cloneNode() Node.cloneNode(deep) 

appendChild()方法存在副作用,cloneNode()复制节点副本,不会删除原节点。参数deep是否采用深度克隆,如果为true, 则该节点的所有后代节点也都会被克隆,如果为false,则只克隆该节点本身

删除DOM
Node.removeChild() 
需要删除的节点和其父节点的引用;

Node.parentNode.removeChild(this) 
删除一个仅基于自身引用的节点;

3.常见问题
在指定节点后面插入节点;在指定节点的前面插入子节点

4.解决方案
在指定节点的前面插入子节点

function appendChildPre(parent , newNode){
if(parent.length>=1){
// 如果存在子节点,则在第一个子节点的前面添加
parent.insertBefore(newNode , parent.firstNode);
}else{
// 如果不存在,则在最后添加
parent.appendChild(newNode);
}
}

在指定节点的后面插入节点

function insertAfter(newNode, thisNode){
var parent = thisNode.parentNode;
if (parent.lastChild == thisNode) {
// 如果父节点的最后一个节点是指定节点,则直接添加
parent.appendChild(newNode);
}else {
parent.insertBefore(newNode , thisNode.nextSibling);
//如果不是,则在指定节点的下一个节点前面插入
}
}

5.编码实战
demo
6.扩展思考
7.参考文献
参考一 MDN文档操作

参考二 廖雪峰 JavaScript 教程

参考三 JavaScript 教程

8.更多讨论
问:什么是文档碎片?

答:createDocumentFragment() 用来创建文档碎片节点。 

文档碎片节点是若干DOM节点的集合,可以包括各种类型的节点,如 元素节点、文本节点、注释节点 等。文档碎片节点在创建之初是空的,需要向它添加节点。 

语法: document.createDocumentFragment();

问:innerText和textContent有什么区别?

答:   textContent 会获取所有元素的内容,包括<script> 和 <style> 元素,然而 IE 专有属性 innerText 不会。

innerText 会受样式的影响,它不返回隐藏元素的文本,但 textContent 返回。

由于 innerText 受 CSS 样式的影响,它会触发重排(reflow),但textContent 不会。

与 textContent 不同的是, 在 Internet Explorer (对于小于等于 IE11 的版本) 中对 innerText 进行修改, 不仅会移除当前元素的子节点,而且还会永久性地销毁所有内部文本节点(由此导致无法再将这些被销毁的文本节点插入到当前元素或任何其他元素中)。

问:innerText和textContent浏览器支持度?

答:IE、Safari、Opera和Chrome支持innerText属性。Firefox虽然不支持innerText,但支持作用类似的textContent属性。textContent是DOM3级规定的一个属性,而且也得到了safari、opera和Chrome的支持。


用户bPbdDlb
422 声望36 粉丝