基本概念

DOM 是 JavaScript 操作网页的接口,全称为“文档对象模型”(Document Object Model)。它的作用是将网页转为一个 JavaScript 对象,从而可以用脚本进行各种操作(比如增删内容)。

JavaScript 也是最常用于 DOM 操作的语言

 

节点

DOM的最小组成单位叫做节点(node)。文档的树形结构(DOM树),就是由各种不同类型的节点组成。每个节点可以看作是文档树的一片叶子。

节点的类型有七种。

•  Document:整个文档树的顶层节点

•  DocumentType:doctype标签(比如<!DOCTYPE html>)

•  Element:网页的各种HTML标签(比如<body>、<a>等)

•  Attribute:网页元素的属性(比如class="right")

•  Text:标签之间或标签包含的文本

•  Comment:注释

•  DocumentFragment:文档的片段

这七种节点都属于浏览器原生提供的节点对象的派生对象,具有一些共同的属性和方法。

 

 

节点树

一个文档的所有节点,按照所在的层级,可以抽象成一种树状结构。这种树状结构就是DOM。

最顶层的节点就是document节点,它代表了整个文档。文档里面最高一层的HTML标签,一般是<html>,它构成树结构的根节点(root node),其他HTML标签节点都是它的下级。

除了根节点以外,其他节点对于周围的节点都存在三种关系。

•  父节点关系(parentNode):直接的那个上级节点

•  子节点关系(childNodes):直接的下级节点

•  同级节点关系(sibling):拥有同一个父节点的节点

 

特征相关的属性

所有节点对象都是浏览器内置的Node对象的实例,继承了Node属性和方法。这是所有节点的共同特征。

以下属性与节点对象本身的特征相关。

 

 

Node.nodeName,Node.nodeType

nodeName属性返回节点的名称,nodeType属性返回节点类型的常数值

 

以document节点为例,它的nodeName属性等于#document,nodeType属性等于9。

 

document.nodeName // "#document"

document.nodeType // 9

 

Node.nodeValue

Node.nodeValue属性返回一个字符串,表示当前节点本身的文本值,该属性可读写。

 

 

Node.textContent

Node.textContent属性返回当前节点和它的所有后代节点的文本内容。

// HTML代码为

// <div id="divA">This is <span>some</span> text</div>

 

document.getElementById('divA').textContent

// This is some text

textContent属性自动忽略当前节点内部的HTML标签,返回所有文本内容。

 

 

Node.baseURI

Node.baseURI属性返回一个字符串,表示当前网页的绝对路径。如果无法取到这个值,则返回null。浏览器根据这个属性,计算网页上的相对路径的URL。该属性为只读。

// 当前网页的网址为

// http://www.example.com/index.html

document.baseURI

// http://www.example.com/index.html

 

相关节点的属性

Node.ownerDocument

 

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

 

var d = p.ownerDocument;

d === document // true

document对象本身的ownerDocument属性,返回null。

 

Node.nextSibling

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

 

Node.previousSibling

 

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

 

// html 代码如下

// <a><span id="b1"></span><span id="b2"></span></a>

 

document.getElementById('b1').previousSibling // null

document.getElementById('b2').previousSibling.id // "b1"

对于当前节点前面有空格,则previousSibling属性会返回一个内容为空格的文本节点。

 

 

Node.parentNode

parentNode属性返回当前节点的父节点

 

Node.parentElement

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

 

Node.childNodes

childNodes属性返回一个NodeList集合,成员包括当前节点的所有子节点。注意,除了HTML元素节点,该属性返回的还包括Text节点和Comment节点。

var ulElementChildNodes = document.querySelector('ul').childNodes;

 

Node.firstChild,Node.lastChild

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

 

<p id="para-01"><span>First span</span></p>

 

<script type="text/javascript">

  console.log(

    document.getElementById('para-01').firstChild.nodeName

  ) // "SPAN"

</script>

上面代码中,p元素的第一个子节点是span元素。

 

 

上面代码中,p元素与span元素之间有空白字符,这导致firstChild返回的是文本节点。

 

 

 

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

 

 

 

节点对象的方法

Node.appendChild()

Node.appendChild方法接受一个节点对象作为参数,将其作为最后一个子节点,插入当前节点。

 

var p = document.createElement('p');

document.body.appendChild(p);

如果参数节点是DOM中已经存在的节点,appendChild方法会将其从原来的位置,移动到新位置。

 

 

Node.hasChildNodes()

Node.hasChildNodes方法返回一个布尔值,表示当前节点是否有子节点。

 

var foo = document.getElementById("foo");

 

if (foo.hasChildNodes()) {

  foo.removeChild(foo.childNodes[0]);

}

上面代码表示,如果foo节点有子节点,就移除第一个子节点。

 

 

Node.cloneNode()

Node.cloneNode方法用于克隆一个节点。它接受一个布尔值作为参数,表示是否同时克隆子节点,默认是false,即不克隆子节点。

 

var cloneUL = document.querySelector('ul').cloneNode(true);

需要注意的是,克隆一个节点,会拷贝该节点的所有属性,但是会丧失addEventListener方法和on-属性(即node.onclick = fn),添加在这个节点上的事件回调函数。

 

 

Node.insertBefore()

insertBefore方法用于将某个节点插入当前节点内部的指定位置。它接受两个参数,第一个参数是所要插入的节点,第二个参数是当前节点内部的一个子节点,新的节点将插在这个子节点的前面。

var text1 = document.createTextNode('1');

var li = document.createElement('li');

li.appendChild(text1);

 

var ul = document.querySelector('ul');

ul.insertBefore(li, ul.firstChild);

上面代码使用当前节点的firstChild属性,在<ul>节点的最前面插入一个新建的<li>节点,新节点变成第一个子节点。

 

Node.removeChild()

Node.removeChild方法接受一个子节点作为参数,用于从当前节点移除该子节点。它返回被移除的子节点。

 

var divA = document.getElementById('A');

divA.parentNode.removeChild(divA);

上面代码是如何移除一个指定节点。

 

 

Node.replaceChild()

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

 

replacedNode = parentNode.replaceChild(newChild, oldChild);

下面是一个例子。

 

var divA = document.getElementById('A');

var newSpan = document.createElement('span');

newSpan.textContent = 'Hello World!';

divA.parentNode.replaceChild(newSpan, divA);

 

 

Node.contains()

Node.contains方法接受一个节点作为参数,返回一个布尔值,表示参数节点是否为当前节点的后代节点。

 

document.body.contains(node)

上面代码检查某个节点,是否包含在当前文档之中。

Node.isEqualNode()

 

isEqualNode方法返回一个布尔值,用于检查两个节点是否相等。所谓相等的节点,指的是两个节点的类型相同、属性相同、子节点相同。

 

var targetEl = document.getElementById("targetEl");

var firstDiv = document.getElementsByTagName("div")[0];

 

targetEl.isEqualNode(firstDiv)

 

 

Node.normalize()

 

normailize方法用于清理当前节点内部的所有Text节点。它会去除空的文本节点,并且将毗邻的文本节点合并成一个。

 

var wrapper = document.createElement("div");

 

wrapper.appendChild(document.createTextNode("Part 1 "));

wrapper.appendChild(document.createTextNode("Part 2 "));

 

wrapper.childNodes.length // 2

 

wrapper.normalize();

 

wrapper.childNodes.length // 1

上面代码使用normalize方法之前,wrapper节点有两个Text子节点。使用normalize方法之后,两个Text子节点被合并成一个。

 

 

但是,一般不把它们当作函数使用,甚至都没有直接使用它们的场合。


NodeList对象
NodeList实例对象是一个类似数组的对象,它的成员是节点对象。Node.childNodes、document.querySelectorAll()返回的都是NodeList实例对象。

var parent = document.getElementById('parent');
parent.childNodes.length // 2
parent.appendChild(document.createElement('div'));
parent.childNodes.length // 3
上面代码中,parent.childNodes返回的是一个NodeList实例对象。当parent节点新增一个子节点以后,该对象的成员个数就增加了1。


HTMLCollection对象

HTMLCollection实例对象与NodeList实例对象类似,也是节点的集合,返回一个类似数组的对象。document.links、docuement.forms、document.images等属性,返回的都是HTMLCollection实例对象。

ParentNode接口,ChildNode接口

ParentNode接口
ParentNode接口用于获取Element子节点。Element节点、Document节点和DocumentFragment节点,部署了ParentNode接口。凡是这三类节点,都具有以下四个属性,用于获取Element子节点。

children
children属性返回一个动态的HTMLCollection集合,由当前节点的所有Element子节点组成。

下面代码遍历指定节点的所有Element子节点。

if (el.children.length) {
for (var i = 0; i < el.children.length; i++) {
// ...
}
}

firstElementChild
firstElementChild属性返回当前节点的第一个Element子节点,如果不存在任何Element子节点,则返回null。

document.firstElementChild.nodeName
// "HTML"

上面代码中,document节点的第一个Element子节点是<HTML>。

 

lastElementChild
lastElementChild属性返回当前节点的最后一个Element子节点,如果不存在任何Element子节点,则返回null。

document.lastElementChild.nodeName
// "HTML"
上面代码中,document节点的最后一个Element子节点是<HTML>。

childElementCount

childElementCount属性返回当前节点的所有Element子节点的数目。

ChildNode 接口
ChildNode接口用于处理子节点(包含但不限于Element子节点)。Element节点、DocumentType节点和CharacterData接口,部署了ChildNode接口。凡是这三类节点(接口),都可以使用下面四个方法。

remove()

remove方法用于移除当前节点。

el.remove()
上面方法在DOM中移除了el节点。注意,调用这个方法的节点,是被移除的节点本身,而不是它的父节点。

(2)before()

before方法用于在当前节点的前面,插入一个同级节点。如果参数是节点对象,插入DOM的就是该节点对象;如果参数是文本,插入DOM的就是参数对应的文本节点。

(3)after()

after方法用于在当前节点的后面,插入一个同级节点。如果参数是节点对象,插入DOM的就是该节点对象;如果参数是文本,插入DOM的就是参数对应的文本节点。

(4)replaceWith()

replaceWith方法使用参数指定的节点,替换当前节点。如果参数是节点对象,替换当前节点的就是该节点对象;如果参数是文本,替换当前节点的就是参数对应的文本节点。

 

  

posted on 2018-02-26 09:07  Sharpest  阅读(286)  评论(0)    收藏  举报