深入理解dom节点

656 阅读5分钟

一、节点概念

在 HTML DOM 中,所有事物都是节点。DOM 是被视为节点树的 HTML。节点树如下图所示,就是一棵普普通通平凡无实的树

二、节点类型

目前节点类型有12种,包括已废弃的节点类型以及XML节点类型。而在html中比较常见的节点的类型为6种,分别为元素节点、文本节点、注释节点、文档节点、文档类型节点以及文档片段节点。在html中,每一种节点都有其节点类型nodetype,通过获取节点类型,我们就可以知道当前节点是什么类型的节点。常量与节点的对应关系具体可以看以下汇总表,资料参考来源MDN

(ps:由于IE8-浏览器中的所有DOM对象都是以COM对象的形式实现的。所以,IE8-浏览器并不支持Node对象的写法)

下面我们将展开来唠唠在html中的6种节点类型。

1、元素节点

元素节点是DOM文档树的主要节点之一,也是我们比较熟悉的节点类型,如header、body、div等等。 举个例子:

<div id="div">123</div>
<script>
//=> 1 "DIV" null true
console.log(div.nodeType,div.nodeName,div.nodeValue,div.nodeType === Node.ELEMENT_NODE);
</script>

特定的属性以及方法

所有属性继承自它的祖先接口 Node,并且扩展了 Node 的父接口 EventTarget。

因为是基本的节点类型,所以元素节点的属性以及方法实在是太太太多了,相信大扎都比较熟悉了,这里就不一一列举凑篇幅了。

2、文本节点

顾名思义,文本节点即指向文本的节点,在html里面看到一切的文字信息都属于文本节点。

<div id="div">我是div标签</div>
<script>
//=> 3 "#text" "我是div标签" true
console.log(div.firstChild.nodeType,div.firstChild.nodeName,div.firstChild.nodeValue,div.firstChild.nodeType === Node.TEXT_NODE);
</script>

创建一个文本节点

// 构造函数 (构造函数方法在ie上不支持)
var text1 = new Text('我是文本节点');
// dom操作
var text2 = document.createTextNode('我是文本节点');

空白节点

关于文本节点,遇到最多的兼容问题是空白文本节点问题。IE8-浏览器不识别空白文本节点,而其他浏览器会识别空白文本节点。

特定的属性以及方法

  • Text.wholeText

这个属性的作用是把与此文本节点相连的其他文本节点作为一个整体返回。一般情况下,文本节点的data、nodeValue以及wholeText返回的数据是一样的,但是在某些情况下,例如js动态添加文本节点,splitText把文本节点拆成几个文本节点时,wholeText属性才真正发挥出它的作用。

  • Text.splitText

splitText方法接受一个number类型的参数,按照参数分割nodeValue值,将文本节点分成两个文本节点。并返回拆隔出来的新的文本节点的内容。

<div id="text">我是文本节点</div>
<script>
  //=> 文本节点
  text.firstChild.splitText(2)
  //=> 我是
  console.log(text.firstChild.data)
  //=> 我是文本节点
  console.log(text.firstChild.wholeText)
</script>

3、注释节点

注释节点comment表示网页中的HTML注释。

<div id="div">
  <!-- <div>我是注释内容</div> -->
  我是div标签
</div>
<script>
  var comment = div.childNodes[1]
  //=> 8 #comment  <div>我是注释内容</div>  true
  console.log(comment.nodeType, comment.nodeName, comment.nodeValue, comment.nodeType === Node.COMMENT_NODE);
</script>

创建一个文本节点

// 构造函数 (构造函数在ie上不支持)
var comment1 = new Comment('我是注释节点');
// dom操作
var comment2 = document.createComment('我是注释节点');

特定的属性以及方法

该接口没有特定的属性,但是从其父类 CharacterData 继承属性,以及间接从 Node 继承部分属性。

4、文档节点

文档节点即根节点,指向document对象,故而没有parentNode

<!DOCTYPE html>
<html lang="zh-cn">
	...
</html>
<script>
 	//=> #document 9 null true
	console.log(document.nodeName, document.nodeType, document.nodeValue,document.nodeType === Node.DOCUMENT_NODE);
</script>

特定的属性以及方法

document继承自 Node 和 EventTarget 接口。故Node操作和EventTarget方法都能使用。 同时document的属性和方法也是灰常之多,特定的属性和方法相信大扎都知道了,这里就不一一列举凑篇幅了(其实就是懒,不我不是)。

5、文档类型节点

文档类型节点包含着与文档的doctype有关的所有信息。

<!DOCTYPE html>
<html lang="zh-cn">
	...
</html>
<script>
 	//=> html 10 null true (ps:IE8-浏览器将标签名为"!"的元素视作注释节点,所以IE8-浏览器返回notype为8)
  	var dom = document.firstChild;
  	//或var dom = document.doctype;  IE8-浏览器不支持document.doctype
	console.log(dom.nodeName, dom.nodeType, dom.nodeValue, dom.nodeType === Node.DOCUMENT_TYPE_NODE);
</script>

特定的属性以及方法

该接口其继承 Node 的全部方法及属性,并实现了 ParentNode 接口中的方法。

  • DocumentType.name

DOMString,文档类型的名称,例:中的“html”

  • DocumentType.publicId

一个DOMString,例:HTML5中的空字符串——"-//W3C//DTD HTML 4.01//EN"。

  • DocumentType.systemId

一个DOMString,例:HTML5中的空字符串——

6、文档片段节点

在所有节点类型中,只有文档片段节点DocumentFragment在文档中没有对应的标记。它被作为一个轻量版的 Document 使用,就像标准的document一样,存储由节点(nodes)组成的文档结构。与document相比,最大的区别是DocumentFragment 不是真实 DOM 树的一部分,它的变化不会触发 DOM 树的重新渲染,且不会导致性能等问题。

最常用的方法是使用文档片段作为参数(例如,任何 Node 接口类似 Node.appendChild 和 Node.insertBefore 的方法),这种情况下被添加(append)或被插入(inserted)的是片段的所有子节点, 而非片段本身。因为所有的节点会被一次插入到文档中,而这个操作仅发生一个重渲染的操作,而不是每个节点分别被插入到文档中,因为后者会发生多次重渲染的操作。

//=> #document-fragment 11 null true
var fragment = document.createDocumentFragment();  	
console.log(fragment.nodeName, fragment.nodeType, fragment.nodeValue, fragment.nodeType === Node.DOCUMENT_FRAGMENT_NODE);

创建一个文档片段节点

// 构造函数 (构造函数方法在ie上不支持)
var text1 = new DocumentFragment()
// dom操作
var text2 = document.createDocumentFragment();

特定的属性以及方法

该接口没有特定的属性和方法,其继承 Node 的全部方法及属性,并实现了 ParentNode 接口中的方法。

最后

写这篇文章也是源于冲浪时一张node节点类型图,当时只列举了常用的几种类型,当时也是没有深究,只是随手截图保存,直至近日整理的时候,才决定写篇文章加深一下印象?嗯嘛如果文中有写得不对的地方,欢迎指出~