DOM (Document Object Model)
DOM定义了表示和修改文档所需方法。DOM对象即为宿主对象,由浏览器厂商定义,用来操作html
和xml
功能的一类对象的集合。
节点(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属性会将它们转为实体形式&
、<
、>
。
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结构树,继承关系的一些问题
获取元素节点函数的一些注意点
- getElementById方法定义在Document.prototype上,即Element节点上不能使用。
- getElementsByName方法定义在HTMLDocument.prototype上,即非html中的document(如xml中的document、Element节点)不能使用。
- getElementsByTagName方法定义在Document.prototype和Element.prototype上,即HTML、xml中的document和Element节点都能使用,所以
getElementsByTagName
比较常用。 - getElementsByClassName、querySelector、querySelectorAll在Document.prototype和Element.prototype类中均有定义。