Js DOM

🍹 DOM,即文档对象模型,是一个编程接口,允许通过JavaScript访问和操作HTML和XML文档的结构、样式以及内容。

1 DOM概述

  • Dom概述
    • 网页被加载时浏览器会创建页面的文档对象模型,即Document Object Model(DOM)。
    • 通过这个对象模型,JavaScript获得创建动态HTML的所有力量。
      • JavaScript能改变页面中的所有HTML元素、HTML属性,以及CSS样式。
      • JavaScript能删除已有的HTML元素和属性,也能添加新的HTML元素和属性。
      • JavaScript能对页面所有已有的HTML事件作出反应,能创建新的HTML事件。
    • 因此,HTML DOM是获取、更改、添加或删除HTML元素的标准。

2 DOM节点

  • DOM节点
    • 节点Node,是构成网页的最基本组成部分,网页中的每个部分都可以称为一个节点。
    • 例如:html标签、属性、文本、注释、整个文档等都是一个节点,但是具体类型不同。
    • 常用节点
      • 属性节点(Attribute)
        • 元素属性,属性节点非元素节点的子节点而是其一部分,通过元素节点获取指定的属性节点。
        • 例如:元素节点.getAttributeNode("属性名"),根据元素节点的属性名获取属性节点对象。
      • 文档节点(Document)
        • 文档节点代表整个HTML文档,网页中的所有节点都是其子节点。
        • document对象作为window对象的属性存在,不用获取直接使用。
      • 文本节点(Text)
        • 指HTML标签以外的文本内容,任意非HTML的文本都是文本节点。
        • 一般作为元素节点的子节点存在,先获取元素节点再获取文本节点。
        • 例如:元素节点.firstChild;,获取元素节点的第一个子节点。
      • 元素节点
        • HTML文档中的HTML标签,最常用的节点,通过document方法获取。
        • 例如:document.getElementById(),根据id属性获取元素节点对象。

3 DOM操作

  • DOM操作
    • 文档对象代表网页,如果想要访问HTML页面中的任何元素,需要从访问document对象开始。
    • document对象是一个全局对象,代表当前加载的HTML文档,可访问页面各个元素、属性等。

3-1 查找HTML元素

1
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
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>查找HTML元素</title>
</head>

<body style="text-align: center">
<br /><br />
<input type="submit" value="我是 submit 提交按钮" /><br /><br />
<button id="btn1">我是 id 为 btn1 的按钮</button>
<br /><br />
<button id="btn2">我是 id 为 btn2 的按钮</button>
<br /><br />
<button id="btn3" class="btn3" value="btn3">我是 id 为 btn3 的按钮</button>

<!-- JavaScript由上到下执行 -->
<script>
// 通过“元素id”获取按钮节点对象
var btn1 = document.getElementById("btn1");
console.log(btn1);

// 通过“类名”获取按钮节点对象数组
var btn2 = document.getElementsByClassName("btn2");
console.log(btn2);

// 通过“标签名”获取按钮节点对象数组
var btn3 = document.getElementsByTagName("input");
console.log(btn3);

// 通过“CSS选择器”选择“单个”按钮,class为btn3的按钮
var btn4 = document.querySelector(".btn3");
console.log(btn4);

// 通过“CSS选择器”选择“所有”按钮
var btn5 = document.querySelectorAll("button");
console.log(btn5);
</script>
</body>

</html>

3-2 修改HMTL元素

  • 修改HMTL元素
    • document.createElement():创建HTML元素节点。
    • document.createAttribute():创建HTML属性节点。
    • document.createTextNode():创建HTML文本节点。
    • 元素节点.removeChild(element):删除HTML元素。
    • 元素节点.appendChild(element):添加HTML元素。
    • 元素节点.replaceChild(element):替换HTML元素。
    • 元素节点.insertBefore(element):在指定的子节点前插入新的子节点。

(1) 方法使用

1
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>方法使用</title>
<style>
ul {
/* 容器居中 */
text-align: center;
}

li {
display: block;
}
</style>
</head>

<body>
<ul id="ul">
<li id="id1">列表项1</li>
<li id="id2">列表项2</li>
<li id="id3">列表项3</li>
<li id="id4">列表项4</li>
</ul>

<!-- JavaScript由上到下执行 -->
<script>
// 创建一个ul列表,然后在该列表中追加4个li标签
var ul = document.createElement("ul");

// 方法一
var li1 = document.createElement("li");
var text1 = document.createTextNode("青天有月来几时,我今停杯一问之:");
li1.appendChild(text1);
ul.appendChild(li1);
var li2 = document.createElement("li");
var text2 = document.createTextNode("人攀明月不可得,月行却与人相随?");
li2.appendChild(text2);
ul.appendChild(li2);
var li3 = document.createElement("li");
var text3 = document.createTextNode("皎如飞镜临丹阙,绿烟灭尽清辉发?");
li3.appendChild(text3);
ul.appendChild(li3);
var li4 = document.createElement("li");
var text4 = document.createTextNode("但见宵从海上来,宁知晓向云间没?");
li4.appendChild(text4);
ul.appendChild(li4);

// 方法二
var li5 = document.createElement("li");
li5.innerHTML = "白兔捣药秋复春,嫦娥孤栖与谁邻?";
ul.appendChild(li5);

var li6 = document.createElement("li");
li6.innerHTML = "今人不见古时月,今月曾经照古人。";
ul.appendChild(li6);

var li7 = document.createElement("li");
li7.innerHTML = "古人今人若流水,共看明月皆如此。";
ul.appendChild(li7);

var li8 = document.createElement("li");
li8.innerHTML = "唯愿当歌对酒时,月光长照金樽里。";
ul.appendChild(li8);

// 方法三
var lia = "<li>汉文皇帝有高台,此日登临曙色开。</li>";
var lib = "<li>三晋云山皆北向,二陵风雨自东来。</li>";
var lic = "<li>关门令尹谁能识,河上仙翁去不回。</li>";
var lid = "<li>且欲近寻彭泽宰,陶然共醉菊花杯。</li>";
ul.innerHTML = lia + lib + lic + lid;

document.getElementsByTagName("body")[0].appendChild(ul);

// 替换最后一个li,在第一个li前边插入一个id为0的li,删除第一个li
var ul = document.getElementById("ul");
var id1 = document.getElementById("id1");
var id4 = document.getElementById("id4");

// 替换最后一个
var replaceLi = document.createElement("li");
replaceLi.innerHTML = "替换成4";
ul.replaceChild(replaceLi, id4);

// 在第一个li前边插入一个id为id0的li
var id0 = document.createElement("li");
id0.innerHTML = "插入为0";
ul.insertBefore(id0, id1);

// 删除第一个
ul.removeChild(id1);
</script>
</body>

</html>

(2) 动态操作

1
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>动态操作</title>
<style>
.b1 {
width: 100px;
height: 100px;
background-color: greenyellow;
margin: 0 auto;
}

.b2 {
width: 100px;
height: 100px;
background-color: yellow;
margin: 0 auto;
}
</style>
</head>

<body style="text-align: center">
<button id="btn0">判断 b2 样式</button><br /><br />
<button id="btn1">添加 b2 样式</button><br /><br />
<button id="btn2">删除 b2 样式</button><br /><br />
<button id="btn3">切换 b2 样式</button><br /><br />
<div id="box" class="b1"></div>

<!-- JavaScript由上到下执行 -->
<script>
var btn0 = document.getElementById("btn0");
var btn1 = document.getElementById("btn1");
var btn2 = document.getElementById("btn2");
var btn3 = document.getElementById("btn3");
var box = document.getElementById("box");

btn0.onclick = function () {
alert(hasClass(box, "b2"));
};
btn1.onclick = function () {
addClass(box, "b2");
};
btn2.onclick = function () {
removeClass(box, "b2");
};
btn3.onclick = function () {
toggleClass(box, "b2");
};

/*
* 判断一个元素中是否含有指定的class属性值
* 如果有该class则返回true,没有则返回false
*/
function hasClass(obj, cn) {
var reg = new RegExp("\\b" + cn + "\\b");
return reg.test(obj.className);
}

/*
* 向一个元素中添加指定的class属性值
* 参数:
* obj 要添加的class属性元素
* cn 要添加的class值
*/
function addClass(obj, cn) {
// 检查obj中是否含有cn
if (!hasClass(obj, cn)) {
obj.className += " " + cn;
}
}

/*
* 删除一个元素中指定的class属性
*/
function removeClass(obj, cn) {
var reg = new RegExp("\\b" + cn + "\\b");
obj.className = obj.className.replace(reg, "");
}

/*
* toggleClass可以用来切换一个类
* 如果元素中具有该类,则删除
* 如果元素中没有该类,则添加
*/
function toggleClass(obj, cn) {
// 判断obj中是否含有cn
if (hasClass(obj, cn)) {
// 存在,则删除
removeClass(obj, cn);
} else {
// 没有,则添加
addClass(obj, cn);
}
}
</script>
</body>

</html>

3-3 获取HTML的值

1
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
81
82
83
84
85
86
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>获取HTML的值</title>
<style>
#box {
width: 200px;
height: 200px;
background: green;
/* 上下margin为0,左右margin为auto */
margin: 0 auto;
}
</style>
</head>

<body style="text-align: center">
<br /><br />
<button id="btn">我是 id 为 btn 的按钮</button><br /><br />
<div id="header">
<h1>header 中的标题</h1>
</div>
<a id="a" href="https://www.baidu.com/">打开百度,你就知道!</a><br /><br />
<div style="width: 100px; height: 100px; background: greenyellow" id="box"></div>

<!-- JavaScript由上到下执行 -->
<script>
var btn = document.getElementById("btn");
// 获取按钮的文本内容
console.log(btn.innerText);

var header = document.getElementById("header");
// 获取header的innerHTML
console.log(header.innerHTML);

var a = document.getElementById("a");
// 获取a的href属性值
console.log(a.href);
// 获取a的href属性值
console.log(a.getAttribute("href"));

var box = document.getElementById("box");
// 获取box行内background的样式值
// 通过style属性设置和读取的都是内联样式,无法读取正在应用的样式
console.log("背景色显示:", box.style.background);

// 想要读取当前正在应用的样式属性可以使用元素.currentStyle.样式名来获取
// 若当前元素没设置该样式,则获取默认值,但是currentStyle只有IE浏览器支持
// 其它浏览器使用getComputedStyle()获取,该方法是window的方法,可直接使用
// 需两个参数:第一个参数获取样式的元素,第二个参数传递一个伪元素,一般都传null
/* 通用的获取元素样式的方法 */
function getStyle(obj, name) {
if (window.getComputedStyle) {
// 正常浏览器的方式,具有getComputedStyle()方法
return getComputedStyle(obj, null)[name];
} else {
// IE8的方式,没有getComputedStyle()方法
return obj.currentStyle[name];
}
}
var box = document.getElementById("box");
console.log("获取到的正在运用的实际宽:", getStyle(box, "width"));
console.log("获取到的正在运用的实际高:", getStyle(box, "height"));
console.log(
"获取到的正在运用的实际背景色:",
getStyle(box, "background")
);

// 编写一段兼容性代码,用来获取任意标签的文本内容
/* 获取任意标签的内容 */
function getInnerText(element) {
// 判断浏览器是否支持textContent
// 支持则使用textContent获取内容,否则使用innerText获取内容
if (typeof element.textContent == "undefined") {
return element.innerText;
} else {
return element.textContent;
}
}
var a = document.getElementById("a");
console.log("兼容性代码所获取到的文本内容:", getInnerText(a));
</script>
</body>

</html>

3-4 修改HTML的值

1
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>修改HTML的值</title>
<style>
#box {
/* 上下margin为0,左右margin为auto */
margin: 0 auto;
}
</style>
</head>

<body style="text-align: center">
<br /><br />
<button id="btn">我是 id 为 btn 的按钮</button><br /><br />
<div id="header">
<h1>header 中的标题</h1>
</div>
<a id="a" href="">打开百度,你就知道!</a><br /><br />
<div style="width: 100px; height: 100px; background: greenyellow" id="box"></div>
<br /><br />
<div id="insert">
<p>大鹏一日同风起,扶摇直上九万里。</p>
</div>

<!-- JavaScript由上到下执行 -->
<script>
var btn = document.getElementById("btn");
// 修改按钮的文本内容
btn.innerText = "这是 JavaScript 的按钮";
console.log(btn);

var header = document.getElementById("header");
// 修改header的innerHTML
header.innerHTML = "<h3>我是 header 中的标题</h3>";
console.log(header);

var a = document.getElementById("a");
// 修改a的href属性值
a.href = "https://www.baidu.com/";
console.log(a);
// 修改a的href属性值
a.setAttribute("href", "https://www.hao123.com/");
console.log(a);

var box = document.getElementById("box");
// 修改box行内background的样式值
box.style.background = "orange";
console.log(box);

// insertAdjacentText(where, text)在指定地方插入文本
// insertAdjacentHTML(where, html)在指定地方插入html代码
// where:beforeBegin >>> 开始标签前、beforeEnd >>> 结束标签前
// where:afterBegin >>> 开始标签后、afterEnd >>> 结束标签后
// insertAdjacentHTML插入html代码后,页面上的元素集合将发生变化
// insertAdjacentHTML插入script脚本文件时,必须在script元素上定义defer属性
// insertAdjacentHTML不适用于单个的空元素标签,例如:img、input等
// 这两个方法必须等文档加载好后才能执行,否则报错
var div = document.getElementById("insert");
// 相当于在<p>标签前插入文本内容
div.insertAdjacentHTML("beforeBegin", "大鹏一日同风起,扶摇直上九万里。");

// 编写一段兼容性代码,用来设置任意标签的文本内容
/* 获取任意标签的内容 */
function getInnerText(element) {
// 判断浏览器是否支持textContent
// 如果支持,则使用textContent获取内容,否则使用innerText获取内容
if (typeof element.textContent == "undefined") {
return element.innerText;
} else {
return element.textContent;
}
}

/* 设置任意标签的内容 */
function setInnerText(element, text) {
// 判断浏览器是否支持textContent
// 如果支持,则使用textContent设置内容,否则使用innerText设置内容
if (typeof element.textContent == "undefined") {
return (element.innerText = text);
} else {
return (element.textContent = text);
}
}

var a = document.getElementById("a");
setInnerText(a, "你确定要打开百度网址吗?");
console.log(getInnerText(a));
</script>
</body>

</html>

3-5 查找HTML父子

1
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>查找HTML父子</title>
<style>
ul {
display: block;
justify-content: center;
list-style-type: none;
padding: 0;
}

li {
margin: 0 10px;
text-align: center;
}
</style>
</head>

<body style="text-align: center">
<div id="container">
<p>前面的段落标签</p>
<b>加粗的文本内容</b><br />
<a href="https://www.baidu.com" id="a">百度一下,你就知道!</a><br />
<i>斜体的文本内容</i><br />
<p>最后的段落标签</p>
</div>
<br />
<div id="box">
<ul id="ul">
<li id="id1"><a href="https://www.baidu.com">超链接 1</a></li>
<li id="id2"><a href="https://www.baidu.com">超链接 2</a></li>
<li id="id3"><a href="https://www.baidu.com">超链接 3</a></li>
<li id="id4"><a href="https://www.baidu.com">超链接 4</a></li>
</ul>
</div>
<!-- JavaScript由上到下执行 -->
<script>
// 第一个子元素
var firstNode = getfirstElementChild(
document.getElementById("container")
);
console.log(firstNode.innerHTML);
// 最后一个子元素
var lastNode = getLastElementChild(document.getElementById("container"));
console.log(lastNode.innerHTML);
// 指定元素的前一个子元素
var node1 = getPreviousElementSibling(document.getElementById("a"));
console.log(node1.innerHTML);
// 指定元素的后一个子元素
var node2 = getNextElementSibling(document.getElementById("a"));
console.log(node2.innerHTML);

/* 获取任意一个父级元素的第一个子元素 */
function getfirstElementChild(element) {
if (element.firstElementChild) {
return element.firstElementChild;
} else {
var node = element.firstChild;
while (node && node.nodeType != 1) {
node = node.nextSibling;
}
return node;
}
}

/* 获取任意一个父级元素的最后一个子元素 */
function getLastElementChild(element) {
if (element.lastElementChild) {
return element.lastElementChild;
} else {
var node = element.lastChild;
while (node && node.nodeType != 1) {
node = node.previousSibling;
}
return node;
}
}

/* 获取任意一个子元素的前一个兄弟元素 */
function getPreviousElementSibling(element) {
if (element.previousElementSibling) {
return element.previousElementSibling;
} else {
var node = element.previousSibling;
while (node && node.nodeType != 1) {
node = node.previousSibling;
}
return node;
}
}

/* 获取任意一个子元素的后一个兄弟元素 */
function getNextElementSibling(element) {
if (element.nextElementSibling) {
return element.nextElementSibling;
} else {
var node = element.nextSibling;
while (node && node.nodeType != 1) {
node = node.nextSibling;
}
return node;
}
}

var box = document.getElementById("box");
var ul = document.getElementById("ul");
var li = document.getElementById("id3");

// 返回元素的父节点
console.log(li.parentNode);
// 返回元素的父元素
console.log(li.parentElement);

// 返回元素的第一个子元素,不包含空白文本Text节点
console.log(ul.firstElementChild);
// 返回元素的最后一个子元素,不包含空白文本Text节点
console.log(ul.lastElementChild);
// 返回指定元素的前一个兄弟元素,相同节点树层中的前一个元素节点
console.log(li.previousElementSibling);
// 返回指定元素的后一个兄弟元素,相同节点树层中的下一个元素节点
console.log(li.nextElementSibling);

// 返回元素的最后一个子节点,包含空白文本Text节点
console.log(ul.lastChild);
// 返回元素的第一个子节点,包含空白文本Text节点
console.log(ul.firstChild);
// 返回某个元素紧接之前节点,包含空白文本Text节点
console.log(li.previousSibling);
// 返回某个元素紧接之后节点,包含空白文本Text节点
console.log(li.nextSibling);

// 返回元素的一个子元素的集合,不包含空白文本Text节点
console.log(box.children);
// 返回元素的一个子节点的数组,包含空白文本Text节点
console.log(box.childNodes);
</script>
</body>

</html>

4 窗口事件

1
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
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>窗口事件</title>
</head>

<body style="text-align: center">
<!-- JavaScript由上到下执行 -->
<script>
// 由窗口触发,同样适用于<body>标签
window.onblur = function () {
console.log("窗口正在失去焦点!");
};
window.onfocus = function () {
console.log("窗口正在获取焦点!");
};
window.onload = function () {
console.log("页面文档加载输出!");
};
window.onresize = function () {
console.log("正在改变窗口大小!");
};
window.onstorage = function () {
console.log(
"当Web Storage区域更新时(存储空间的数据发生变化时)运行脚本!"
);
};
</script>
</body>

</html>

5 表单事件

1
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
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>表单事件</title>
</head>

<body style="text-align: center">
<form>
<input type="text" id="text" required /><br /><br />
<input type="submit" value="submit" />
</form>
<br />
<form id="myform">
<input type="submit" id="submit" />
</form>
<!-- JavaScript由上到下执行 -->
<script>
// 在HTML表单中触发,适用于所有HTML元素
var textInput = document.getElementById("text");

// 文本框失去焦点时,背景色为绿色
textInput.onblur = function () {
this.style.background = "green";
};

// 文本框获取焦点时,背景色为黄绿色
textInput.onfocus = function () {
this.style.background = "greenyellow";
};

// 文本框内容改变,鼠标离开文本框时,自动将文本框内容输出到控制台
textInput.onchange = function () {
console.log(this.value);
};

// 文本框内容改变时,立即将改变的文本框内容输出到控制台
textInput.oniput = function () {
console.log(this.value);
};

// 单击submit,不填写文本字段将警报
textInput.oninvalid = function () {
console.log("请完整填写表单内容!");
};

// 选中文本框内容时,输出已选择文本框内容
textInput.onselect = function () {
console.log("您已选择文本框内容!");
};

var myform = document.getElementById("myform");
// 提交表单时,控制台输出表单已经提交
myform.onsubmit = function () {
console.log("您的表单已经提交啦!");
// 用来阻止表单提交,不写会跳转请求
return false;
};
</script>
</body>

</html>

6 键鼠事件

  • 键鼠事件
    • 当事件的响应函数被触发时,浏览器每次都会将一个事件对象作为实参传递给响应函数。
    • Event对象代表事件状态,比如:事件在其中发生的元素、键盘按键的状态、鼠标位置等。
    • 键鼠属性
      • altKey:当事件被触发时,ALT键是否被按下。
      • ctrlKey:当事件被触发时,CTRL键是否被按下。
      • shiftKey:当事件被触发时,SHIFT键是否被按下。
      • screenX:当事件被触发时,鼠标指针相对于用户屏幕的水平坐标。
      • screenY:当事件被触发时,鼠标指针相对于用户屏幕的垂直坐标。
      • clientX:当事件被触发时,鼠标指针相对于浏览器窗口的水平坐标。
      • clientY:当事件被触发时,鼠标指针相对于浏览器窗口的垂直坐标。
1
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
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>键鼠事件</title>
</head>

<body style="text-align: center">
<!-- JavaScript由上到下执行 -->
<script>
document.addEventListener("keydown", function (event) {
if (event.altKey) {
console.log("ALT键被按下");
}
if (event.ctrlKey) {
console.log("CTRL键被按下");
}
if (event.shiftKey) {
console.log("SHIFT键被按下");
}
});

document.addEventListener("mousemove", function (event) {
console.log("鼠标指针的屏幕水平坐标:" + event.screenX);
console.log("鼠标指针的屏幕垂直坐标:" + event.screenY);
});

document.addEventListener("mousemove", function (event) {
console.log("鼠标指针的窗口水平坐标:" + event.clientX);
console.log("鼠标指针的窗口垂直坐标:" + event.clientY);
});
</script>
</body>

</html>

6-1 键盘属性

  • 键盘属性
    • onkeyup:松开按键时运行脚本。
    • onkeydown:按下按键时运行脚本。
    • onkeypress:按下并松开按键时运行脚本。
1
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
81
82
83
84
85
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>键盘属性</title>
<style>
#box {
width: 100px;
height: 100px;
background: yellow;
position: absolute;
top: 80px;
left: 50%;
transform: translateX(-50%);
}
</style>
</head>

<body style="text-align: center">
<br />
<input type="text" id="myInput" placeholder="请输入数字!" /><br />
<div id="box"></div>
<!-- JavaScript由上到下执行 -->
<script>
// 通过键盘触发事件,类似用户行为
// 松开键盘按键时触发
document.getElementById("myInput").onkeyup = function () {
console.log(this.value);
};

// 按下按键,判断当前按键是否为a,是则输出true,否则输出false
window.onkeydown = function (event) {
// IE8中响应函数被触发时,浏览器不会传递事件对象
// IE8及以下的浏览器是将事件对象作为window对象的属性保存的
// 解决兼容性问题
event = event || window.event;

if (event.keyCode == 65) {
console.log("true");
} else {
console.log("false");
}
};

// 使div可根据不同的方向键向不同方向移动
var box = document.getElementById("box");

// 为document绑定一个按键按下的事件
document.onkeydown = function (event) {
event = event || window.event;

// 定义移动速度
var speed = 10;

// 选择移动方向
switch (event.keyCode) {
case 37:
box.style.left = box.offsetLeft - speed + "px";
break;
case 39:
box.style.left = box.offsetLeft + speed + "px";
break;
case 38:
box.style.top = box.offsetTop - speed + "px";
break;
case 40:
box.style.top = box.offsetTop + speed + "px";
break;
}
};

// 按下并松开按键时触发
document.getElementById("myInput").onkeypress = function (event) {
// 获取按键的ASCII码
var key = event.which || event.keyCode;
// 如果按键不是数字,则阻止输入
if (key < 48 || key > 57) {
event.preventDefault();
}
};
</script>
</body>

</html>

6-2 鼠标属性

  • 鼠标属性
    • onclick:单击鼠标时运行脚本。
    • ondblclick:双击鼠标时运行脚本。
    • onscroll:滚动元素滚动条时运行脚本。
    • onmouseup:松开鼠标按钮时运行脚本。
    • onmousedown:按下鼠标按钮时运行脚本。
    • onmousemove:鼠标指针移动时运行脚本。
    • onmousewheel:转动鼠标滚轮时运行脚本。
    • onmouseleave:鼠标指针移出元素时运行脚本,可以阻止冒泡。
    • onmouseout:鼠标指针移出元素时运行脚本,不可以阻止冒泡。
    • onmouseenter:鼠标指针移至元素之上时运行脚本,可以阻止冒泡。
    • onmouseover:鼠标指针移至元素之上时运行脚本,不可以阻止冒泡。
1
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>鼠标属性</title>
<style>
#box1,
#box2 {
width: 300px;
height: 105px;
background: yellow;
position: absolute;
/* 垂直居中 */
top: 50%;
transform: translateY(-50%);
}

#box1 {
/* 水平位置调整 */
left: calc(50% - 300px);
/* 允许滚动 */
overflow-y: scroll;
}

#box2 {
left: calc(50% + 50px);
}
</style>
</head>

<body style="text-align: center">
<div id="box1">
《豫章行》·李白〔唐代〕<br />
胡风吹代马,北拥鲁阳关。<br />
吴兵照海雪,西讨何时还。<br />
半渡上辽津,黄云惨无颜。<br />
老母与子别,呼天野草间。<br />
白马绕旌旗,悲鸣相追攀。<br />
白杨秋月苦,早落豫章山。<br />
本为休明人,斩虏素不闲。<br />
岂惜战斗死,为君扫凶顽。<br />
精感石没羽,岂云惮险艰。<br />
楼船若鲸飞,波荡落星湾。<br />
此曲不可奏,三军鬓成斑。
</div>
<div id="box2"></div>
<!-- JavaScript由上到下执行 -->
<script>
// 通过鼠标触发事件,类似用户行为
window.onclick = function () {
console.log("单击鼠标");
};

window.ondblclick = function () {
console.log("双击鼠标");
};

var box1 = document.getElementById("box1");
var box2 = document.getElementById("box2");

box1.onscroll = function () {
console.log("滚动元素", this.scrollTop);
};

box1.onmousewheel = function (event) {
console.log("滚轮滚动", event.wheelDelta);
};

box1.onmouseout = function () {
console.log("移出元素");
};

box1.onmouseover = function () {
console.log("移至元素");
};

// 鼠标移入div,背景色变为黄绿色
box1.onmouseenter = function () {
this.style.background = "greenyellow";
};

// 鼠标移出div,背景色变为橙色
box1.onmouseleave = function () {
this.style.background = "orange";
};

// drag(box1);
drag(box2);

function drag(obj) {
// 鼠标在被拖拽元素上按下时,开始拖拽
obj.onmousedown = function (event) {
// 解决事件的兼容性问题
event = event || window.event;
// 设置obj捕获所有鼠标按下的事件
// obj.setCapture && obj.setCapture();
if (obj.setPointerCapture) {
obj.setPointerCapture(event.pointerId);
}
// obj的偏移量:鼠标.clentX - 元素.offsetLeft
// obj的偏移量:鼠标.clentY - 元素.offsetTop
var ol = event.clientX - obj.offsetLeft;
var ot = event.clientY - obj.offsetTop;

// 为document绑定一个鼠标移动事件
document.onmousemove = function (event) {
// 解决事件的兼容性问题
event = event || window.event;
// 当鼠标移动时被拖拽元素跟随鼠标移动
// 获取鼠标的坐标
var left = event.clientX - ol;
var top = event.clientY - ot;
// 修改obj的位置
obj.style.left = left + "px";
obj.style.top = top + "px";
};

// 为document绑定一个鼠标松开事件
document.onmouseup = function () {
// 取消document的onmousemove事件
document.onmousemove = null;
// 取消document的onmouseup事件
document.onmouseup = null;
// 当鼠标松开时,取消对事件的捕获
// obj.releaseCapture && obj.releaseCapture();
if (obj.releasePointerCapture) {
obj.releasePointerCapture(event.pointerId);
}
};
// 当拖拽一个网页内容时,浏览器会默认去搜索引擎中搜索内容
// 会导致拖拽功能的异常,这是浏览器提供的默认行为
// 若不希望发生该行为,通过以下代码取消,但对IE8不起作用
return false;
};
}
</script>
</body>

</html>

7 媒体事件

  • 媒体事件
    • 通过视频(videos)、图像(images)、音频(audio)触发事件。
    • 媒体属性
      • onabort:发生中止事件时运行脚本。
      • onpause:媒介数据暂停时运行脚本。
      • onended:媒介抵达结尾时运行脚本。
      • onloadeddata:加载媒介数据时运行脚本。
      • onplay:媒介数据将要开始播放时运行脚本。
      • onplaying:媒介数据已开始播放时运行脚本。
      • onerror:元素加载期间发生错误时运行脚本。
      • ondurationchange:媒介长度改变时运行脚本。
      • onprogress:浏览器正在取媒介数据时运行脚本。
      • ontimeupdate:媒介改变其播放位置时运行脚本。
      • onloadstart:浏览器开始加载媒介数据时运行脚本。
      • onratechange:媒介数据的播放速率改变时运行脚本。
      • onwaiting:媒介已停止播放但打算继续播放时运行脚本。
      • onstalled:取回媒介数据过程中(延迟)存在错误时运行脚本。
      • onreadystatechange:就绪状态(ready-state)改变时运行脚本。
      • onseeking:媒介元素的定位属性为真,且定位已开始时运行脚本。
      • oncanplay:媒介能开始播放,但可能因缓冲而需要停止时运行脚本。
      • onseeked:媒介元素的定位属性不再为真,且定位已结束时运行脚本。
      • onvolumechange:媒介改变音量亦或当音量被设置为静音时运行脚本。
      • oncanplaythrough:媒介无需因缓冲而停止即可播放至结尾时运行脚本。
      • onloadedmetadata:媒介元素的持续时间及其它媒介数据已加载时运行脚本。
      • onemptied:媒介资源元素突然为空时(例如网络错误、加载错误等)运行脚本。
      • onsuspend:浏览器正在取媒介数据但在取回整个媒介文件前停止时运行脚本。
1
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
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>媒体事件</title>
</head>

<body style="text-align: center">
<br />
<video id="myVideo" width="320" height="240" controls>
<source src="movie.mp4" type="video/mp4" />
您的浏览器不支持 Video 标签。
</video>
<div id="loadStatus">视频尚未开始加载</div>
<!-- JavaScript由上到下执行 -->
<script>
// 通过视频、图像、音频触发,获取视频和状态显示元素
var video = document.getElementById("myVideo");
var loadStatus = document.getElementById("loadStatus");

// 当视频开始加载时,更新状态显示元素
video.onloadstart = function () {
loadStatus.innerHTML = "视频开始加载...";
};
</script>
</body>

</html>

8 其他事件

1
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
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>其他事件</title>
<style>
#myMenu {
display: inline;
}
</style>
</head>

<body style="text-align: center">
<br />
<menu id="myMenu" type="context"><br />
<menuitem label="Option 1">Option 1</menuitem><br />
<menuitem label="Option 2">Option 2</menuitem><br />
<menuitem label="Option 3">Option 3</menuitem>
</menu><br /><br />
<details id="myDetails">
<summary>More Information</summary>
<p>Here is some more information about this product.</p>
</details>
<!-- JavaScript由上到下执行 -->
<script>
// 当<menu>元素在上下文显示时触发
// <menu>元素和onshow事件在HTML5中并不常用
// 而且在大多数现代浏览器中并不被完全支持
document.getElementById("myMenu").onshow = function () {
console.log("Context menu is shown.");
};

// 当用户打开或关闭<details>元素时触发
document.getElementById("myDetails").ontoggle = function () {
if (this.open) {
console.log("<details>元素被打开");
} else {
console.log("<details>元素被关闭");
}
};
</script>
</body>

</html>

9 事件处理

  • 事件处理
    • 事件冒泡、事件委派等主要涉及如何捕获和处理用户与网页交互时所产生的事件。
    • 这些概念是前端开发中处理用户交互的重要组成部分,有利于管理事件及其响应。

9-1 事件冒泡

  • 事件冒泡
    • 事件的向上传导,后代元素的事件被触发时,其祖先元素的相同事件也会被触发。
    • 开发中大部分情况冒泡都是有用的,若不希望发生事件冒泡可通过事件对象取消。
1
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
81
82
83
84
85
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>事件冒泡</title>
<style>
#div1 {
width: 200px;
height: 200px;
background: pink;
margin: 0 auto;
display: flex;
justify-content: center;
align-items: center;
}

#div2 {
width: 100px;
height: 100px;
background: coral;
margin: 0 auto;
}
</style>
</head>

<body style="text-align: center">
<p>div1</p>
<div id="div1">
<div id="div2">div2</div>
</div>
<br />
<a href="https://www.baidu.com" id="a">打开百度,你就知道!</a>
<!-- JavaScript由上到下执行 -->
<script>
var div1 = document.getElementById("div1");
var div2 = document.getElementById("div2");

// 为div1绑定单击事件
div1.onclick = function () {
console.log("div1 的单击事件被触发!");
stopBubble();
};

// 为div2绑定单击事件
div2.onclick = function () {
// 点击div2会触发div1和div2的单击事件
console.log("div2 的单击事件被触发!");
stopBubble();
};

// 取消事件冒泡
function stopBubble(event) {
// 如果提供了事件对象,则这是一个非IE浏览器
if (event && event.stopPropagation) {
// 因此支持W3C的stopPropagation()方法
event.stopPropagation();
} else {
// 否则需要使用IE的方式来取消事件冒泡
window.event.cancelBubble = true;
}
}

var a = document.getElementById("a");

// 为a绑定单击事件
a.onclick = function () {
stopDefault();
};

// 阻止浏览器的默认行为
function stopDefault(event) {
if (event && event.preventDefault) {
// 阻止默认浏览器动作(W3C)
event.preventDefault();
} else {
// IE中阻止函数器默认动作的方式
window.event.returnValue = false;
}
return false;
}
</script>
</body>

</html>

9-2 事件委派

  • 事件委派
    • 只绑定一次事件,就可应用到多个元素上,即使元素是后续添加的。
    • 可以尝试将事件绑定给元素的共同祖先元素上,也就是事件的委派。
    • 当后代元素的事件触发时,会冒泡到祖先元素,从而通过响应函数处理事件。
    • 事件委派利用了事件冒泡,通过委派可以减少事件绑定的次数,并提高性能。
1
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
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>事件委派</title>
<style>
li {
display: block;
}
</style>
</head>

<body style="text-align: center">
<ul id="u1">
<li><a href="javascript:;" class="link">超链接 1</a></li>
<li><a href="javascript:;" class="link">超链接 2</a></li>
<li><a href="javascript:;" class="link">超链接 3</a></li>
</ul>
<!-- JavaScript由上到下执行 -->
<script>
var u1 = document.getElementById("u1");

// 为ul绑定一个单击响应函数
u1.onclick = function (event) {
event = event || window.event;
// 如果触发事件的对象是期望元素则执行,否则不执行
if (event.target.className == "link") {
console.log("我是ul的单击响应函数");
}
};
</script>
</body>

</html>

9-3 事件绑定

1
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
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>事件绑定</title>
</head>

<body style="text-align: center">
<button id="btn1">按钮 1</button>
<button id="btn2">按钮 2</button>
<!-- JavaScript由上到下执行 -->
<script>
function f1() {
console.log("output 1 ...");
}

function f2() {
console.log("output 2 ...");
}

// 为按钮1的单击事件绑定两个函数
addEventListener(document.getElementById("btn1"), "click", f1);
addEventListener(document.getElementById("btn1"), "click", f2);

// 点击按钮2取消按钮1的单机事件绑定函数f1
document.getElementById("btn2").onclick = function () {
removeEventListener(document.getElementById("btn1"), "click", f1);
};

/* 为元素绑定事件兼容性代码 */
function addEventListener(element, type, fn) {
if (element.addEventListener) {
element.addEventListener(type, fn, false);
} else if (element.attachEvent) {
element.attachEvent("on" + type, fn);
} else {
element["on" + type] = fn;
}
}

/* 为元素解绑事件兼容性代码 */
function removeEventListener(element, type, fnName) {
if (element.removeEventListener) {
element.removeEventListener(type, fnName, false);
} else if (element.detachEvent) {
element.detachEvent("on" + type, fnName);
} else {
element["on" + type] = null;
}
}
</script>
</body>

</html>

9-4 事件传播

  • 事件传播
    • 微软:事件由内向外传播,事件触发时,先触发当前元素上的事件,然后向祖先元素传播。
    • 网景:事件由外向内传播,事件触发时,先触发当前元素的最外层祖先元素,再向内传播。
    • W3C综合
      • 捕获阶段:先从最外层的祖先元素向目标元素进行事件捕获,默认不触发。
      • 目标阶段:事件捕获到目标元素,捕获结束后开始在目标元素上触发事件。
      • 冒泡阶段:事件从目标元素向祖先元素传递,依次触发祖先元素上的事件。
    • 如果希望捕获阶段就触发事件,可将addEventListener()的第三个参数设置为true。
    • IE8及以下浏览器中没有捕获阶段,可使用event.stopPropagation();取消事件传播。

Js DOM
https://stitch-top.github.io/2024/08/23/web/web01-javascript/javascript04-js-dom/
作者
Dr.626
发布于
2024年8月23日 21:00:50
许可协议