# JavaScript教程 - 16 DOM
DOM 继续!
# 16.10 节点操作
上面介绍如何查找元素,以及修改元素的文本和属性。
下面来介绍如何添加、删除、替换节点,实现页面的更新。
# 1 添加节点
上面介绍了如何获取节点和修改节点的属性,下面来学习如何创建节点并添加到页面上,以及删除节点。
举个栗子:
下面在点击按钮的时候,动态的向 <ul>
列表中添加 <li>
元素。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>For技术栈</title>
<script>
window.onload = function () {
// 首先获取到ul,然后操作在ul中添加元素
const parent = document.getElementById('course-wrapper');
// 获取按钮
const addButton = document.getElementById('add-button');
// 给按钮添加点击事件
addButton.onclick = function() {
// 创建<li>
const li = document.createElement('li');
// 对li元素进行设置
li.textContent = 'JavaScript教程';
// appendChild给节点添加子节点
parent.appendChild(li);
};
};
</script>
</head>
<body>
<button id="add-button">添加</button>
<ul id="course-wrapper">
<li>HTML5教程</li>
<li>CSS3教程</li>
</ul>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
- 首先使用
document.createElement('li')
来创建<li>
元素; - 然后使用
appendChild()
方法,给节点的最后添加子元素。
显示如下:
上面在添加节点的时候,是添加到父节点的末尾,还可以指定一个兄弟节点,将节点插入到兄弟节点之前:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>For技术栈</title>
<script>
window.onload = function () {
// 首先获取到ul,然后操作在ul中添加元素
const parent = document.getElementById('course-wrapper');
const cssCourse = document.getElementById('css-li');
// 获取按钮
const addButton = document.getElementById('add-button');
// 给按钮添加点击事件
addButton.onclick = function() {
// 创建<li>
const li = document.createElement('li');
// 对li元素进行设置
li.textContent = 'JavaScript教程';
// 将<li>插入到cssCourse节点之前
parent.insertBefore(li, cssCourse);
};
};
</script>
</head>
<body>
<button id="add-button">添加</button>
<ul id="course-wrapper">
<li>HTML5教程</li>
<li id="css-li">CSS3教程</li>
</ul>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
- 在上面的代码中,使用
parent.insertBefore(li, cssCourse);
将<li>
插入到cssCourse
节点之前。
还有一个 insertAdjacentElement()
方法,它可以将元素添加到父元素的前面、后面、父元素中第一个位置和父元素最后的位置。
举个栗子:
let target = document.getElementById("target");
let newDiv = document.createElement("div");
newDiv.textContent = "新的元素";
target.insertAdjacentElement("beforebegin", newDiv); // 在 target 前面,和target同级
target.insertAdjacentElement("afterend", newDiv); // 在 target 后面,和target同级
target.insertAdjacentElement("afterbegin", newDiv); // 作为target的第一个子元素
target.insertAdjacentElement("beforeend", newDiv); // 作为target的最后一个子元素
2
3
4
5
6
7
8
9
上面在添加节点的时候,首先创建节点,并设置节点的属性,然后将节点添加到页面中,这样操作稍微有一点麻烦。我们还可以直接使用 HTML 字符串进行添加。
举个栗子:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>For技术栈</title>
<script>
window.onload = function () {
// 首先获取到ul,然后操作在ul中添加元素
const parent = document.getElementById('course-wrapper');
// 获取按钮
const addButton = document.getElementById('add-button');
// 给按钮添加点击事件
addButton.onclick = function() {
// 直接插入
parent.insertAdjacentHTML("beforeend", "<li>我插进来了</li>");
};
};
</script>
</head>
<body>
<button id="add-button">添加</button>
<ul id="course-wrapper">
<li>HTML5教程</li>
<li id="css-li">CSS3教程</li>
</ul>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
- 使用
insertAdjacentHTML()
可以直接通过字符串来插入节点,同时可以使用beforebegin/afterend/afterbegin/beforeend
指定插入的位置。
# 2 删除节点
删除节点就比较简单了,直接使用 元素.remove()
来删除节点即可。
举个栗子:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>For技术栈</title>
<script>
window.onload = function () {
// 获取删除按钮
const deleteButton = document.getElementById('delete-button');
// 首先获取到ul,然后操作在ul中添加元素
const cssCourse = document.getElementById('css-li');
// 给按钮添加点击事件
deleteButton.onclick = function() {
let judge = confirm('确定删除吗?');
// 确认是否需要删除
if (judge) {
// 直接删除
cssCourse.remove();
}
};
};
</script>
</head>
<body>
<button id="delete-button">删除</button>
<ul id="course-wrapper">
<li>HTML5教程</li>
<li id="css-li">CSS3教程</li>
<li>JavaScript教程</li>
</ul>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
- 点击删除按钮后,就删除了
cssCourse
; - 在上面的代码中,使用
confirm()
来弹出一个提示框,让用户确认是否要删除,点击确认confirm()
会返回 true。
显式如下:
也可以通过父节点来删除,使用 parent.removeChild(child)
,也要获取子节点,那还不如直接使用 元素.remove()
。
# 3 替换节点
方法 parent.replaceChild(newNode, oldNode)
可以用来把 oldNode
从其父节点中移除,并用 newNode
替换它。
举个栗子:
<div id="container">
<p id="old">原来的段落</p>
</div>
2
3
使用新的元素替换上面的 <p>
元素,JS代码如下:
let container = document.getElementById("container");
let old = document.getElementById("old");
let newP = document.createElement("p");
newP.textContent = "这是新的段落";
container.replaceChild(newP, old);
2
3
4
5
6
7
# 4 复制节点
有时候创建节点有点麻烦,我们也可以复制一个节点,然后再进行操作。
举个栗子:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>For技术栈</title>
<script>
window.onload = function () {
// 获取复制按钮
const copyButton = document.getElementById('copy-button');
const target = document.getElementById('css-li');
copyButton.onclick = function() {
// 克隆节点
const cloneNode = target.cloneNode();
cloneNode.id = 'new-id';
// 添加到target后面
target.insertAdjacentElement('afterend', cloneNode);
};
};
</script>
</head>
<body>
<button id="copy-button">复制</button>
<ul id="course-wrapper">
<li>HTML5教程</li>
<li id="css-li">CSS3教程</li>
</ul>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
- 在上面的代码中,通过
cloneNode()
来复制节点,注意,需要修改 id,否则 id 在页面会重复。
上面的代码运行后,点击复制按钮,会发现复制的节点没有内容,如下:
这是为什么呢?
这是因为在使用 cloneNode()
复制节点的时候,只会复制当前节点,不会复制节点中的子节点,所以文本节点不会复制。
我们可以给 cloneNode()
传递 true 参数,这样会将子节点也复制:
const cloneNode = target.cloneNode(true);
这样就可以了。
# 16.11 样式
下面来讲解使用 JavaScript 来操作样式。
# 1 修改样式
修改样式非常的简单,使用 元素.style.样式名称 = 样式值
来修改就可以了。
举个栗子:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>For技术栈</title>
<style>
#div1 {
width: 100px;
height: 100px;
background-color: lightblue;
}
</style>
</head>
<body>
<button id="button1">修改样式</button>
<div id="div1"></div>
<script>
// 获取按钮
const button1 = document.getElementById('button1');
const div1 = document.getElementById('div1');
button1.onclick = function() {
// 修改样式
div1.style.width = "200px";
div1.style.height = "200px";
div1.style.backgroundColor = "pink"
};
</script>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
- 需要注意,通过
元素.style.样式名称
来修改样式的时候,修改的是元素的内联样式。 - 如果css样式名称中包含
-
,则样式名称使用驼峰规则,像background-color
变成backgroundColor
。
# 2 获取样式
同样,通过 元素.style.样式名称
也可以获取样式,但是获取的也是内联样式。
如下:
// 获取按钮
const button1 = document.getElementById('button');
const div1 = document.getElementById('div1');
button1.onclick = function() {
console.log(div1.style.width); // 什么也没用
};
2
3
4
5
6
7
但是如果没有内联样式,那么什么也获取不到。其实如果内联样式不生效(例如样式表使用 !important),那么获取内联样式也没有意义。
所以获取当前标签生效的样式,才有意义,我们可以使用 getComputedStyle()
方法来获取当前元素生效的样式。
举个栗子:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>For技术栈</title>
<style>
#div1 {
height: 100px;
background-color: lightblue;
}
</style>
</head>
<body>
<button id="button1">获取样式</button>
<div id="div1"></div>
<script>
// 获取按钮
const button1 = document.getElementById('button1');
const div1 = document.getElementById('div1');
button1.onclick = function() {
// 获取div1生效的样式
const div1Style = getComputedStyle(div1);
console.log(div1Style.width); // 794px
console.log(div1Style.height); // 100px
console.log(div1Style.backgroundColor); // rgb(173, 216, 230)
console.log(div1Style.left); // auto
};
</script>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
- 通过
getComputedStyle(元素对象)
可以返回一个对象,其中包含了元素生效的所有样式,然后就可以获取各个样式; - 需要注意,获取到的样式是字符串类型的,例如长宽,带有
px
,所以如果要进行运算,需要先转换为数字,例如使用parseInt()
转换。 - 上面的 div 是没有设置宽度的,理论上宽度是
auto
,但是获取的时候能获取到具体的宽度值,但是left
是auto
,获取的时候只能获取到auto
,所以获取样式的时候需要样式的值。
如果要获取元素的伪元素的样式,可以通过如下方式获取:
const beforeStyle = getComputedStyle(div1, "::before");
这个了解一下,很少用到。
# 3 其他获取样式的方式
还有几种可以获取样式的方式,介绍一下。
先看代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>For技术栈</title>
<style>
#div1 {
width: 100px;;
height: 100px;
padding: 30px;
border: 10px red solid;
margin: 30px;
background-color: lightblue;
overflow: scroll;
}
#div2 {
width: 50px;
height: 400px;
background-color: pink;
}
</style>
</head>
<body>
<button id="button1">获取样式</button>
<div id="div1">
<div id="div2"></div>
</div>
<script>
// 获取按钮
const button1 = document.getElementById('button1');
const div1 = document.getElementById('div1');
button1.onclick = function () {
console.log(div1.clientWidth); // 160,获取元素的可见宽度,包含内容区100和padding30*2
console.log(div1.clientHeight); // 160
console.log(div1.offsetWidth); // 180,获取元素的宽度,包含内容区100、padding*2和border*2
console.log(div1.offsetHeight); // 180
console.log(div1.scrollWidth); // 160,获取元素滚动区域的大小,横向没有溢出,此时和clientWidth相同
console.log(div1.scrollHeight); // 460,div2的高度+padding*2
};
</script>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
- 在上面的代码中,就是 div1 包含 div2,设置了 两个 div 的尺寸和背景颜色,div2 的尺寸从 div1 中溢出了,设置 div1 显示滚动条。
- 通过
clientWidth
、offsetWidth
、scrollWidth
可以获取元素相应的尺寸。
显示如下:
还有两个属性页介绍一下,offsetTop
和 offsetLeft
用于获取元素相对于其最近定位祖先元素的垂直和水平偏移距离。
举个栗子:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>For技术栈</title>
<style>
#div1 {
position: relative;
width: 100px;;
height: 100px;
padding: 30px;
background-color: lightblue;
}
#div2 {
position: absolute;
top: 50px;
left: 50px;
width: 50px;
height: 50px;
background-color: pink;
}
</style>
</head>
<body>
<button id="button1">获取样式</button>
<div id="div1">
<div id="div2"></div>
</div>
<script>
// 获取按钮
const button1 = document.getElementById('button1');
const div2 = document.getElementById('div2');
button1.onclick = function () {
console.log(div2.offsetParent); // 获取到定位的父元素,也就是div1
console.log(div2.offsetTop); // 50
console.log(div2.offsetLeft); // 50
};
</script>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
显示如下:
- 定位祖先元素是指开启了定位的祖先元素,
position
为relative
、absolute
、fixed
或sticky
的祖先元素,都没有那就是body元素。
如果不设置 div2 的 top 和 left 属性,那么 div2 在 div1 中的位置是受 div1 的padding 影响的,此时 div2.offsetTop
值为30。
我们一般获取元素的宽高,都会使用上面的方法,使用 getComputedStyle() 获取宽高用的不多。
注意:上面的属性都是只读的。
还有两个属性,我们可以获取到它们的值,也可以修改它们的值,scrollTop
和 scrollLeft
可以获取和设置滚动条的位置。
举个栗子:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>For技术栈</title>
<style>
#div1 {
width: 100px;;
height: 100px;
padding: 30px;
background-color: lightblue;
overflow: scroll;
}
#div2 {
width: 50px;
height: 400px;
background-color: pink;
}
</style>
</head>
<body>
<button id="button1">获取样式</button>
<div id="div1">
<div id="div2"></div>
</div>
<script>
// 获取按钮
const button1 = document.getElementById('button1');
const div1 = document.getElementById('div1');
button1.onclick = function () {
console.log(div1.scrollTop); // 0, 滚动条没滚动的时候是0
div1.scrollTop = 30; // 设置垂直滚动到30px
};
</script>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
- 可以通过
元素.scrollTop
和元素.scrollLeft
获取和设置垂直滚动条和水平滚动条的位置。
还可以通过 window.scrollTo(0, 100);
设置窗口滚动到垂直位置 100px
处,第一个参数是水平位置,第二个参数是垂直位置。
# 4 修改class
前面通过 style 来修改样式,但是这种方式只能一个一个属性进行修改,如果属性太多,修改起来会比较麻烦,而且 JS 代码和 CSS 样式会比较耦合,所以我们可以直接修改标签的 class 属性。
举个栗子:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>For技术栈</title>
<style>
.class1 {
width: 100px;
height: 100px;
background-color: lightgreen;
}
.class2 {
background-color: lightblue;
}
.class3 {
background-color: pink;
}
.class4 {
width: 200px;
height: 200px;
}
</style>
</head>
<body>
<button id="button1">添加样式</button>
<button id="button2">移除样式</button>
<button id="button3">切换样式</button>
<button id="button4">替换样式</button>
<button id="button5">检查样式</button>
<div id="div1" class="class1"></div>
<script>
// 获取按钮
const button1 = document.getElementById('button1');
const button2 = document.getElementById('button2');
const button3 = document.getElementById('button3');
const button4 = document.getElementById('button4');
const button5 = document.getElementById('button5');
const div1 = document.getElementById('div1');
button1.onclick = function () {
// 给div1 添加样式
div1.classList.add('class2'); // 添加单个类
div1.classList.add('class2', 'class3', 'class4'); // 还可以添加多个类
};
button2.onclick = function () {
// 移除样式
div1.classList.remove('class2'); // 移除单个类
div1.classList.remove('class1', 'class3'); // 还可以移除多个类
};
button3.onclick = function () {
// 切换样式
div1.classList.toggle('class2'); // 切换类,没有就添加,有就删除
// div1.classList.toggle('active', true); // 强制添加
// div1.classList.toggle('active', false); // 强制移除
};
button4.onclick = function () {
// 替换样式
div1.classList.replace('class2', 'class3'); // 将class1替换为class3,如果没有class1,不会替换
};
button5.onclick = function () {
// 检查样式
const hasClass = div1.classList.contains('class2'); // 检查是否存在class2
console.log(hasClass);
};
</script>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
- 在上面的代码中,分别演示了添加、删除、切换、替换和检查是否包含某个class。需要先获取到元素的
classList
才可以操作。
在以前是通过 className
操作的,是有点麻烦:
const element = document.getElementById('myElement');
element.className = 'new-class'; // 替换所有现有类
element.className += ' additional-class'; // 追加类(注意前面的空格)
2
3
了解一下即可。