1、DOM操作梗概
本篇内容实际上在另一篇笔记《从JS和jQuery浅谈DOM操作》已经提到了重点的地方,可以戳链接另外进行阅读。
以前提到过,实际上HTML在被浏览器加载以后,会变成 “一棵DOM树”,里面的节点都是HTML DOM对象,而我们针对于DOM的操作,也就是针对这些节点对象来进行的,一般来说就是增、删、改、查(遍历)操作。
最常见的获取DOM节点的方式,无非是 document.getElementById()、document.getElementsByTagName()、document.getElementsByClassName() 等诸如此类,在这里再说说另一种方式。
还有一种方式是使用 querySelector() 和 querySelectorAll(),需要了解selector语法,这个类似jQuery选择器,十分方便:
// 通过querySelector获取ID为q1的节点
var q1 = document.querySelector('#q1');
// 通过querySelectorAll获取q1节点内的符合条件的所有节点
var ps = q1.querySelectorAll('div.highlighted > p');
5
1
// 通过querySelector获取ID为q1的节点
2
var q1 = document.querySelector('#q1');
3
4
// 通过querySelectorAll获取q1节点内的符合条件的所有节点
5
var ps = q1.querySelectorAll('div.highlighted > p');
但是这种方式,低版本的IE<8是不支持idea,而且IE8也仅仅是有限支持,所以在使用时要注意版本兼容性。
严格地讲,我们这里的DOM节点是指DOM对象,也就是Element,但是DOM节点实际上是Node,在HTML中,Node包括Element、Comment、CDATA_SECTION等很多种,以及根节点Document类型,但是,绝大多数时候我们只关心Element,也就是实际控制页面结构的Node,其他类型的Node忽略即可。根节点Document已经自动绑定为全局变量document。
2、更新DOM
第一种方式可以修改 innerHTML 属性,这个方式不光可以修改文本,同时可以修改HTML:
// 获取<p id="p-id">...</p>
var p = document.getElementById('p-id');
// 设置文本为abc:
p.innerHTML = 'ABC'; // <p id="p-id">ABC</p>
// 设置HTML:
p.innerHTML = 'ABC <span style="color:red">RED</span> XYZ';
// <p>...</p>的内部结构已修改
7
1
// 获取<p id="p-id">...</p>
2
var p = document.getElementById('p-id');
3
// 设置文本为abc:
4
p.innerHTML = 'ABC'; // <p id="p-id">ABC</p>
5
// 设置HTML:
6
p.innerHTML = 'ABC <span style="color:red">RED</span> XYZ';
7
// <p>...</p>的内部结构已修改
第二种方式就是修改 innerText 属性或 textContent 属性,两者区别在于前者不会返回隐藏元素的文本,而后者返回所有文本(IE<9不支持textContent),但是这种方式没办法设置HTML标签:
// 获取<p id="p-id">...</p>
var p = document.getElementById('p-id');
// 设置文本:
p.innerText = '<script>alert("Hi")</script>';
// HTML被自动编码,无法设置一个<script>节点:
// <p id="p-id"><script>alert("Hi")</script></p>
6
1
// 获取<p id="p-id">...</p>
2
var p = document.getElementById('p-id');
3
// 设置文本:
4
p.innerText = '<script>alert("Hi")</script>';
5
// HTML被自动编码,无法设置一个<script>节点:
6
// <p id="p-id"><script>alert("Hi")</script></p>
3、插入DOM
因为innerHTML会替换掉原来的内容,所以我们不能使用这种方式来进行DOM的插入操作。
3.1 插入父节点的最后一个子节点 appendChild
第一种方式我们可以使用 appendChild() 方法,这个方法可以将一个子节点添加到父节点的最后一个子节点:
<!-- HTML结构 -->
<p id="js">JavaScript</p>
<div id="list">
<p id="java">Java</p>
<p id="python">Python</p>
<p id="scheme">Scheme</p>
</div>
//js操作
var js = document.getElementById('js'),
var list = document.getElementById('list');
list.appendChild(js);
<!-- 新的HTML结构 -->
<div id="list">
<p id="java">Java</p>
<p id="python">Python</p>
<p id="scheme">Scheme</p>
<p id="js">JavaScript</p>
</div>
21
1
<!-- HTML结构 -->
2
<p id="js">JavaScript</p>
3
<div id="list">
4
<p id="java">Java</p>
5
<p id="python">Python</p>
6
<p id="scheme">Scheme</p>
7
</div>
8
9
//js操作
10
var js = document.getElementById('js'),
11
var list = document.getElementById('list');
12
list.appendChild(js);
13
14
<!-- 新的HTML结构 -->
15
<div id="list">
16
<p id="java">Java</p>
17
<p id="python">Python</p>
18
<p id="scheme">Scheme</p>
19
<p id="js">JavaScript</p>
20
</div>
21
或者从零创建和插入一个新的节点:
var list = document.getElementById('list'),
var haskell = document.createElement('p');
haskell.id = 'haskell';
haskell.innerText = 'Haskell';
list.appendChild(haskell);
<!-- HTML结构 -->
<div id="list">
<p id="java">Java</p>
<p id="python">Python</p>
<p id="scheme">Scheme</p>
<p id="haskell">Haskell</p>
</div>
13
1
var list = document.getElementById('list'),
2
var haskell = document.createElement('p');
3
haskell.id = 'haskell';
4
haskell.innerText = 'Haskell';
5
list.appendChild(haskell);
6
7
<!-- HTML结构 -->
8
<div id="list">
9
<p id="java">Java</p>
10
<p id="python">Python</p>
11
<p id="scheme">Scheme</p>
12
<p id="haskell">Haskell</p>
13
</div>
3.2 插入指定位置 insertBefore
parentElement.insertBefore(newElement, referenceElement) 这个方法,子节点会插入到referenceElement之前。
<!-- HTML结构 -->
<div id="list">
<p id="java">Java</p>
<p id="python">Python</p>
<p id="scheme">Scheme</p>
</div>
//js操作
var list = document.getElementById('list'),
var ref = document.getElementById('python'),
var haskell = document.createElement('p');
haskell.id = 'haskell';
haskell.innerText = 'Haskell';
list.insertBefore(haskell, ref);
<!-- 新的HTML结构 -->
<div id="list">
<p id="java">Java</p>
<p id="haskell">Haskell</p>
<p id="python">Python</p>
<p id="scheme">Scheme</p>
</div>
x
1
<!-- HTML结构 -->
2
<div id="list">
3
<p id="java">Java</p>
4
<p id="python">Python</p>
5
<p id="scheme">Scheme</p>
6
</div>
7
8
//js操作
9
var list = document.getElementById('list'),
10
var ref = document.getElementById('python'),
11
var haskell = document.createElement('p');
12
haskell.id = 'haskell';
13
haskell.innerText = 'Haskell';
14
list.insertBefore(haskell, ref);
15
16
<!-- 新的HTML结构 -->
17
<div id="list">
18
<p id="java">Java</p>
19
<p id="haskell">Haskell</p>
20
<p id="python">Python</p>
21
<p id="scheme">Scheme</p>
22
</div>
很多时候,我们还需要循环一个父节点的所有子节点,可以通过迭代 children 属性实现:
var i, c,
var list = document.getElementById('list');
for (i = 0; i < list.children.length; i++) {
c = list.children[i]; // 拿到第i个子节点
}
5
1
var i, c,
2
var list = document.getElementById('list');
3
for (i = 0; i < list.children.length; i++) {
4
c = list.children[i]; // 拿到第i个子节点
5
}
4、删除DOM
要删除一个节点,首先要获得该节点本身以及它的父节点,调用父节点的 removeChild 把自己删除:
(要杀掉自己,要先认清自己并找来自己的老爹,让老爹杀死自己,囧jz)
// 拿到待删除节点:
var self = document.getElementById('to-be-removed');
// 拿到父节点:
var parent = self.parentElement;
// 删除:
var removed = parent.removeChild(self);
removed === self; // true
1
// 拿到待删除节点:
2
var self = document.getElementById('to-be-removed');
3
// 拿到父节点:
4
var parent = self.parentElement;
5
// 删除:
6
var removed = parent.removeChild(self);
7
removed === self; // true
如果需要循环遍历删除,一定要注意使用children属性的变化,索引的变化。