-
Notifications
You must be signed in to change notification settings - Fork 0
/
learn_js#5.html
216 lines (173 loc) · 9.84 KB
/
learn_js#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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>事件</title>
</head>
<body>
<!--浏览器事件简介-->
<!--事件是某事发生的信号。所有的 DOM 节点都生成这样的信号(但事件不仅限于 DOM)。-->
<!--这里有一张最有用的 DOM 事件列表,请看:-->
<!--鼠标事件:-->
<!--click —— 当鼠标点击一个元素时(触摸屏设备在 tap 时生成)。-->
<!--contextmenu —— 当鼠标右击一个元素时。-->
<!--mouseover / mouseout —— 当鼠标光标移入或移出一个元素时。-->
<!--mousedown / mouseup —— 当鼠标按下/释放一个元素时。-->
<!--mousemove —— 当鼠标移出时。-->
<!--表单元素事件:-->
<!--submit —— 当访问者提交了一个 <form> 时。-->
<!--focus —— 当访问者聚焦一个元素时,例如 <input>。-->
<!--键盘事件:-->
<!--keydown and keyup —— 当访问者按下然后松开按钮时。-->
<!--Document 事件:-->
<!--DOMContentLoaded —— 当加载和处理 HTML 时,DOM 将会被完整地构建。-->
<!--CSS 事件:-->
<!--transitionend —— 当 CSS 动画完成时。-->
<!--响应函数-->
<script>
function countRabbits() {
for (let i = 1; i <= 3; i++) {
alert("Rabbit number " + i);
}
}
</script>
<input type="button" onclick="countRabbits()" value="Count rabbits!">
<!--一次添加多个响应函数-->
<input id="elem" type="button" value="Click me"/>
<script>
function handler1() {
alert('Thanks!');
}
function handler2() {
alert('Thanks again!');
}
elem.onclick = () => alert("Hello");
elem.addEventListener("click", handler1); // Thanks!
elem.addEventListener("click", handler2); // Thanks again!
</script>
<!--demo:点击之后隐藏一个div标签内的内容-->
<input type="button" id="hider" value="Click to hide the text"/>
<div id="text">Text</div>
<script>
function h() {
let div_text = document.getElementById("text");
div_text.innerHTML = "";
}
document.getElementById("hider").addEventListener("click", h);
</script>
<!--总结-->
<!--有 3 种方法可以分发事件处理器:-->
<!--1. HTML 属性:onclick="..."。-->
<!--2. DOM 属性 elem.onclick = function。-->
<!--3. 方法:添加 elem.addEventListener(event, handler[, phase]),移除 removeEventListener。-->
<!--HTML 属性很少使用,因为 HTML 标签中的 JavaScript 看起来奇怪又陌生。而且也不能在里面写太多的代码。-->
<!--DOM 属性可以使用,但我们不能为特定事件分发多个处理器。在许多场景中,这种限制并不严重。-->
<!--最后一种方法是最灵活的,但也是编写内容最多的。有少数事件只能使用这种方式。-->
<!--例如 transtionend 和 DOMContentLoaded(有待讨论)。当然 addEventListener 也支持对象作为事件处理器。-->
<!--在这种场景下,事件发生时就需要调用 handleEvent 方法。-->
<!--无论你如何分发处理器 —— 它都会将事件对象作为第一个参数。该对象包含事件发生的细节。-->
<!--冒泡和捕获-->
<!--冒泡-->
<!--冒泡原理很简单。-->
<!--当事件发生在元素上,它首先会运行元素本身的处理器,然后运行父元素上的,再然后是其他祖先上的。-->
<!--比如我们有 3 层嵌套 FORM > DIV > P,它们都各自拥有一个处理器:-->
<style>
body * {
margin: 10px;
border: 1px solid blue;
}
</style>
<form onclick="alert('form')">FORM
<div onclick="alert('div')">DIV
<p onclick="alert('p')">P</p>
</div>
</form>
<!--当事件发生在元素上,它首先会运行元素本身的处理器,然后运行父元素上的,再然后是其他祖先上的。-->
<!--事件捕获阶段-->
<!--要在捕获阶段捕获事件,我们需要将 addEventListener 的第三个参数设置为 true。-->
<!--最后一个参数是可选的,有两个可能的值:-->
<!--如果为 false(默认值),则在冒泡阶段设置处理器。-->
<!--如果为 true,则在捕获阶段设置处理器。-->
<form>FORM
<div>DIV
<p>P</p>
</div>
</form>
<script>
for(let elem of document.querySelectorAll('*')) {
elem.addEventListener("click", e => alert(`Capturing: ${elem.tagName}`), true); // 捕获
elem.addEventListener("click", e => alert(`Bubbling: ${elem.tagName}`)); // 冒泡
}
</script>
<!--代码为文档中的每个元素设置点击处理器,以查看哪些元素上的点击事件处理器生效了。-->
<!--如果你点击了 <p>,那么顺序是:-->
<!-- HTML → BODY → FORM → DIV → P(捕获阶段,第一个监听者),然后:-->
<!-- P → DIV → FORM → BODY → HTML(冒泡阶段,第二个监听者)。-->
<!--总结-->
<!--事件处理过程:-->
<!--当事件发生时 —— 嵌套最深的那个元素被标记为“目标事件”(event.target)。-->
<!--然后事件先从文档根节点向下移动到 event.target,过程中调用分配给 addEventListener(...., true) 的处理器。-->
<!--再然后事件从 event.target 向上移动到根,调用使用 on<event> 和 addEventListener 分配的处理器,不使用第三个参数或第三个参数设置为 false。-->
<!-- 每个处理器都可以访问 event 对象属性:-->
<!--event.target —— 事件最深的元素。-->
<!--event.currentTarget (=this) —— 处理事件的当前元素(有处理器在其上运行的)-->
<!--event.eventPhase —— 当前阶段(capturing=1, bubbling=3)。-->
<!--任何事件处理器都可以通过调用 event.stopPropagation() 来停止事件,但不建议如此,-->
<!--因为我们不确定是否后续会使用冒泡上来的事件,也许是完全不同的事情。-->
<!--使用event.target来获取点击的标签-->
<div id="container">
<div class="pane">
<h3>Horse</h3>
<p>The horse is one of two extant subspecies of Equus ferus. It is an odd-toed ungulate mammal belonging to the taxonomic family Equidae. The horse has evolved over the past 45 to 55 million years from a small multi-toed creature, Eohippus, into the large, single-toed animal of today.</p>
<button class="remove-button">[x]</button>
</div>
<div class="pane">
<h3>Donkey</h3>
<p>The donkey or ass (Equus africanus asinus) is a domesticated member of the horse family, Equidae. The wild ancestor of the donkey is the African wild ass, E. africanus. The donkey has been used as a working animal for at least 5000 years.</p>
<button class="remove-button">[x]</button>
</div>
<div class="pane">
<h3>Cat</h3>
<p>The domestic cat (Latin: Felis catus) is a small, typically furry, carnivorous mammal. They are often called house cats when kept as indoor pets or simply cats when there is no need to distinguish them from other felids and felines. Cats are often valued by humans for companionship and for their ability to hunt vermin.
</p>
<button class="remove-button">[x]</button>
</div>
</div>
<script>
// 该closest方法返回当前元素(或当前元素本身)的最接近的祖先,该祖先与参数中给出的选择器匹配。如果没有这样的祖先,它就会返回null。
container.onclick = function(event) {
let target = event.target;
if (target.tagName !== 'BUTTON')
return;
let pane = event.target.closest('.pane');//通过css选择器选择祖先
pane.remove();
};
</script>
<!--浏览器默认动作-->
<!--总结-->
<!--有许多默认浏览器动作:-->
<!--mousedown —— 开始选择(移动鼠标进行选择)。-->
<!--在 <input type="checkbox"> 上 click —— 检查/取消选中的 input。-->
<!--submit —— 单击 <input type="submit"> 或在表单中通过单击 Enter 触发该事件,并在其后浏览器提交表单。-->
<!--wheel —— 鼠标滚轮事件的滚动将作为默认动作。-->
<!--keydown —— 按下按键可能会导致将字符添加到字段,或者触发其他动作。-->
<!--contextmenu —— 事件发生在右击时,动作是显示浏览器上下文菜单。-->
<!--如果我们想要通过 JavaScript 来处理事件,那么所有的默认动作都可以被阻止。-->
<!--想要阻止默认行为 —— 可以使用 event.preventDefault() 或者 return false。第二个方法只适用于分发了 on<event> 的处理器。-->
<!--如果默认动作被阻止,event.defaultPrevented 的值就会变成 true,否则会变成 false。-->
<!--自定义事件-->
<!--总结-->
<!--要生成一个事件,我们首先需要创建一个事件对象。-->
<!--泛型 Event(name, options) 构造器接受任意事件名,options 对象具有两个属性:-->
<!--bubbles: true ,如果事件应该冒泡的话。-->
<!--cancelable: true 则 event.preventDefault() 应该有效。-->
<!--其他像 MouseEvent、KeyboardEvent 这样的原生事件构造器,接受特定于该事件类型的属性。例如,鼠标事件的 clientX。-->
<!--对于自定义事件我们应该使用 CustomEvent 构造器。它有一个名为 detail 的附加选项,我们应该将特定事件的数据指派给它。然后处理器可以以 event.detail 的形式访问它。-->
<!--尽管技术上有可能产生像 click 或者 keydown 这样的浏览器事件,但我们还是该谨慎使用。-->
<!--我们不应该生成浏览器事件,因为这是运行处理器的一种 hacky 方式。大多数来说,这都是一种糟糕的架构。-->
<!--可以生成原生事件:-->
<!--如果他们不提供其他的交互方式,脏黑客行为可以制作第三方库操作所需的方式。-->
<!--对于自动化测试,要在脚本中“单击按钮”并查看接口是否正确反应。-->
<!--使用我们自己的名字来自定义的事件通常是为架构目的产生的,用来指示菜单、滑块、轮播等内部发生什么。-->
</body>
</html>