DOM (Document Object Model)
DOM定义了表示和修改文档所需方法。DOM对象即为宿主对象,由浏览器厂商定义,用来操作htmlxml功能的一类对象的集合。

节点(node)

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

节点的类型有七种。

  • Document:整个文档树的顶层节点
  • DocumentType:doctype标签(比如<!DOCTYPE html>
  • Element:网页的各种HTML标签(比如<body><a>等)
  • Attribute:网页元素的属性(比如class="right"
  • Text:标签之间或标签包含的文本
  • Comment:注释
  • DocumentFragment:文档的片段

浏览器提供一个原生的节点对象Node,上面这七种节点都继承了Node,因此具有一些共同的属性和方法。

节点(node)的一些属性

Node.prototype.nodeType
nodeType属性返回一个整数值,表示节点的类型。

  • 文档节点(document):9
  • 文档类型节点(DocumentType):10
  • 元素节点(element):1
  • 属性节点(attr):2
  • 文本节点(text):3
  • 注释节点(Comment):8
  • 文档片断节点(DocumentFragment):11

Node.prototype.nodeName
nodeName属性返回节点的名称

Node.prototype.nodeValue
nodeValue属性返回当前节点本身的文本值,该属性可读写。 只有文本节点(text)和注释节点(comment)有文本值

遍历节点
Node.prototype.parentNode
parentNode 属性返回当前节点的父节点

Node.prototype.childNodes
childNodes 属性返回当前节点的所有子节点

Node.prototype.firstChild,Node.prototype.lastChild
firstChild属性返回第一个子节点lastChild属性返回最后一个子节点

Node.prototype.previousSibling,Node.prototype.nextSibling
previousSibling属性返回前一个兄弟节点nextSibling属性返回后一个兄弟节点

遍历元素节点
Node.prototype.parentElement
parentElement 属性返回当前节点的父元素节点 (IE9以下不兼容)

ParentNode.children / Element.children
children 属性返回当前节点的所有子元素节点

ParentNode.firstElementChild,ParentNode.lastElementChild / Element.firstElementChild,Element.lastElementChild
firstElementChild属性返回当前节点的第一个子元素节点 (IE9以下不兼容)
lastElementChild 属性返回当前节点的最后一个子元素节点 (IE9以下不兼容)

Element.nextElementSibling,Element.previousElementSibling
nextElementSibling 返回前一个兄弟元素节点 (IE9以下不兼容)
previousElementSibling 返回后一个兄弟元素节点 (IE9以下不兼容)

节点(node)的一些方法

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

插入节点
Node.prototype.appendChild()
appendChild方法接受一个节点对象作为参数,将其作为最后一个子节点,插入当前节点。该方法的返回值就是插入文档的子节点。
如果参数节点是 DOM 已经存在的节点,appendChild方法会将其从原来的位置,移动到新位置。

//新建一个 <p> 节点,将其插入document.body的尾部
var p = document.createElement('p');
document.body.appendChild(p);

Node.prototype.insertBefore()

var insertedNode = parentNode.insertBefore(newNode, referenceNode);

insertBefore方法接受两个参数,第一个参数是所要插入的节点newNode,第二个参数是父节点parentNode内部的一个子节点referenceNode。newNode将插在referenceNode这个子节点的前面。返回值是插入的新节点newNode。

var p = document.createElement('p');
document.body.insertBefore(p, document.body.firstChild);

上面代码中,新建一个<p>节点,插在document.body.firstChild的前面,也就是成为document.body的第一个子节点。
注意,如果所要插入的节点是当前 DOM 现有的节点,则该节点将从原有的位置移除,插入新的位置。


append()、prepend()、before()、after() 这些新的方法存在兼容性问题。

ParentNode.append(),ParentNode.prepend()

append方法为当前节点追加一个或多个子节点,位置是最后一个元素子节点的后面。
该方法不仅可以添加元素子节点,还可以添加文本子节点。

var parent = document.body;

// 添加元素子节点
var p = document.createElement('p');
parent.append(p);

// 添加文本子节点
parent.append('Hello');

// 添加多个元素子节点
var p1 = document.createElement('p');
var p2 = document.createElement('p');
parent.append(p1, p2);

// 添加元素子节点和文本子节点
var p = document.createElement('p');
parent.append('Hello', p);

注意,该方法没有返回值。

prepend方法为当前节点追加一个或多个子节点,位置是第一个元素子节点的前面。它的用法与append方法完全一致,也是没有返回值。

ChildNode.before(),ChildNode.after()
before方法用于在当前节点的前面,插入一个或多个同级节点。两者拥有相同的父节点。
注意,该方法不仅可以插入元素节点,还可以插入文本节点。

var div = document.getElementById('myDiv');

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

// 插入元素节点
div.before(p);

// 插入文本节点
div.before('Hello');

// 插入多个元素节点
div.before(p, span);

// 插入元素节点和文本节点
div.before(p, 'Hello');

after方法用于在当前节点的后面,插入一个或多个同级节点,两者拥有相同的父节点。用法与before方法完全相同。


删除节点
Node.prototype.removeChild()
removeChild方法接受一个子节点作为参数,用于从当前节点移除该子节点。返回值是移除的子节点。如果参数节点不是当前节点的子节点,removeChild方法将报错。

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

ChildNode.remove()
remove方法,移除当前节点

var p = document.getElementsByTagName('p')[0];
p.remove();

document 节点

document对象继承了EventTarget接口、Node接口、ParentNode接口。这意味着,这些接口的方法都可以在document对象上调用。除此之外,document对象还有很多自己的属性和方法。

document 节点的一些属性

document.doctype属性,指向<DOCTYPE>节点,即文档类型(Document Type Declaration,简写DTD)节点。HTML 的文档类型节点,一般写成<!DOCTYPE html>。如果网页没有声明 DTD,该属性返回null

document.documentElement属性返回当前文档的根元素节点(root)。HTML网页的该属性,一般是<html>节点。

document.body,document.head document.body属性指向<body>节点,document.head属性指向<head>节点。

document 节点的一些方法

document 获取 节点的一些方法

document.getElementById()方法返回匹配指定id的元素节点。如果没有发现匹配的节点,则返回null。

document.getElementsByTagName() 方法返回匹配标签名的元素节点。返回的是类数组对象。(最常用

document.getElementsByClassName()方法返回匹配class属性的元素节点,参数可是多个class属性。返回的是类数组对象。(IE8及以下IE版本没有)

document.getElementsByName() 方法返回匹配name属性的元素节点。返回的是类数组对象(旧版本浏览器只有部分标签生效比如表单、img、iframe)

document.querySelector()document.querySelectorAll() document.querySelector方法接受一个 CSS 选择器作为参数,返回一个匹配该选择器的元素节点。document.querySelectorAll方法可返回多个匹配的元素节点,返回的是类数组对象。(IE7及以下IE版本没有,缺陷:不是实时数据)

document 创建 节点的一些方法

document.createElement 方法用来生成元素节点,并返回该节点。
createElement 方法的参数为元素的标签名,即元素节点的tagName属性

var newDiv = document.createElement('div');

document.createTextNode方法用来生成文本节点(Text实例),并返回该节点。createTextNode方法的参数是文本节点的内容。

//新建一个div节点和一个文本节点,然后将文本节点插入div节点
var newDiv = document.createElement('div');
var newContent = document.createTextNode('Hello');
newDiv.appendChild(newContent);

document.createAttribute方法生成一个新的属性节点(Attr实例),并返回它。createAttribute方法的参数name,是属性的名称。

//为div1节点,插入一个值为 newVal 的 my_attrib 属性。
var node = document.getElementById('div1');

var a = document.createAttribute('my_attrib');
a.value = 'newVal';
node.setAttributeNode(a);

// 或者直接
node.setAttribute('my_attrib', 'newVal');

Element (元素节点)

Element 元素节点的一些属性

Element.innerHTML
Element.innerHTML属性返回一个字符串,等同于该元素包含的所有 HTML 代码。该属性可读写,常用来设置某个节点的内容。

el.innerHTML = '';

如果将innerHTML属性设为空,等于删除所有它包含的所有节点。

注意,读取属性值的时候,如果文本节点包含&、小于号(<)和大于号(>),innerHTML属性会将它们转为实体形式&amp;&lt;&gt;

Element.innerText(曾经老版本火狐不兼容,现在可忽略)
Element.textContent(IE8及以下IE版本不兼容)

Element.className,Element.classList
className属性用来读写当前元素节点的class属性。它的值是一个字符串,每个class之间用空格分割。
classList属性返回一个类似数组的对象,当前元素节点的每个class就是这个对象的一个成员。

// HTML 代码 <div class="one two three" id="myDiv"></div>
var div = document.getElementById('myDiv');

div.className
// "one two three"

div.classList
// {
// 	0 : "one"
// 	1 : "two"
// 	2 : "three"
// 	length : 3
// 	value : "one two three"
// }

classList对象有下列方法。

add():增加一个 class。
remove():移除一个 class。
toggle():将某个 class 移入或移出当前元素。
contains():检查当前元素是否包含某个 class。
item():返回指定索引位置的 class。
toString():将 class 的列表转为字符串。

//html 代码为 <div id="myDiv"></div>

var div = document.getElementById('myDiv');

div.classList.add('myClass');
div.classList.add('foo', 'bar');
div.classList.remove('myClass');
div.classList.toggle('myClass'); // 如果 myCssClass 不存在就加入,否则移除
div.classList.contains('myClass'); // 返回 true 或者 false

//html 代码变为 <div id="myDiv" class="foo bar myClass"></div>
Element 元素节点的一些方法

Element.getAttribute()
Element.getAttribute方法返回当前元素节点的指定属性的值。如果指定属性不存在,则返回null。

//html 代码为 <div class="div-1" data-foo="bar"></div>

var div = document.getElementsByTagName('div')[0];
console.log(div.getAttribute('class'));        //div-1
console.log(div.getAttribute('data-foo'));    //bar
console.log(div.getAttribute('id'));         //null

Element.setAttribute()
Element.setAttribute方法用于为当前元素节点新增属性。如果同名属性已存在,则相当于编辑已存在的属性。该方法没有返回值。

//html 代码为 <div></div>
var div = document.getElementsByTagName('div')[0];
div.setAttribute('id','demo');
//html 代码变为 <div id="demo"></div>

只列出常用属性和方法,更多详情移步:
https://wangdoc.com/javascript/dom/element.html


Node结构树,继承关系的一些问题

document在JavaScript使用 javascript的document_元素节点

获取元素节点函数的一些注意点
  1. getElementById方法定义在Document.prototype上,即Element节点上不能使用。
  2. getElementsByName方法定义在HTMLDocument.prototype上,即非html中的document(如xml中的document、Element节点)不能使用。
  3. getElementsByTagName方法定义在Document.prototype和Element.prototype上,即HTML、xml中的document和Element节点都能使用,所以getElementsByTagName比较常用。
  4. getElementsByClassName、querySelector、querySelectorAll在Document.prototype和Element.prototype类中均有定义。