1- # 生成自定义事件
1+ # 创建自定义事件
22
3- 我们不仅可以分发事件 ,还可以从 JavaScript 中生成事件 。
3+ 我们不仅可以分配事件处理程序 ,还可以从 JavaScript 生成事件 。
44
5- 自定义事件可以用于创建 “图形组件”。例如,菜单组件的根元素可以通过触发 ` open ` (打开菜单)、 ` select ` (有一项被选中)等事件告诉菜单发生了什么 。
5+ 自定义事件可用于创建 “图形组件”。例如,我们自己的基于 JavaScript 的菜单的根元素可能会触发 ` open ` (打开菜单), ` select ` (有一项被选中)等事件来告诉菜单发生了什么。另一个代码可能会监听事件,并观察菜单发生了什么 。
66
7- 我们也可以生成一些像 ` click ` 、 ` mousedown ` 此类的内置事件,这些都有利于测试 。
7+ 我们不仅可以生成出于自身目的而创建的全新事件,还可以生成例如 ` click ` 和 ` mousedown ` 等内建事件。这可能会有助于自动化测试 。
88
99## 事件构造器
1010
11- 事件会像 DOM 元素类一样形成层次结构。事件的底层是内置的 [ Event] ( http://www.w3.org/TR/dom/#event ) 类。
11+ 内建事件类形成一个层次结构,类似于 DOM 元素类。根是内建的 [ Event] ( http://www.w3.org/TR/dom/#event ) 类。
1212
1313我们可以像这样创建 ` Event ` 对象:
1414
1515``` js
16- let event = new Event (event type[, options]);
16+ let event = new Event (type[, options]);
1717```
1818
1919参数:
2020
21- - ** event type** —— 可以是任何字符串,比如 ` "click" ` 或者我们自己喜欢的 ` "hey-ho!" ` 。
21+ - ** type** —— 事件类型,可以是像这样 ` "click" ` 的字符串,或者我们自己的像这样 ` "my-event" ` 的参数 。
2222- ** options** —— 具有两个可选属性的对象:
23- - ` bubbles: true/false ` —— 如果是 ` true ` ,那么事件冒泡 。
24- - ` cancelable: true/false ` —— 如果 ` true ` ,那么“默认动作 ”就会被阻止。之后我们会看到对于自定义事件,这些意味着什么 。
23+ - ` bubbles: true/false ` —— 如果为 ` true ` ,那么事件会冒泡 。
24+ - ` cancelable: true/false ` —— 如果为 ` true ` ,那么“默认行为 ”就会被阻止。稍后我们会看到对于自定义事件,它意味着什么 。
2525
26- 默认情况下,它们都是 false:` {bubbles: false, cancelable: false} ` 。
26+ 默认情况下,以上两者都为 false:` {bubbles: false, cancelable: false} ` 。
2727
2828## dispatchEvent
2929
30- 事件对象被创建后,我们应该调用 ` elem.dispatchEvent(event) ` 在元素上 “运行”它。
30+ 事件对象被创建后,我们应该使用 ` elem.dispatchEvent(event) ` 调用在元素上 “运行”它。
3131
32- 然后处理器对其作出反应,就好像它是一个正常的内置事件。如果事件是使用 ` bubbles ` 标志创建的,那么它就会冒泡 。
32+ 然后,处理程序会对它做出反应,就好像它是一个常规的浏览器事件一样。如果事件是用 ` bubbles ` 标志创建的,那么它会冒泡 。
3333
34- 在下面示例中 ,` click ` 事件是用 JavaScript 初始化生成的。处理器执行效果和单击按钮的效果一样 :
34+ 在下面这个示例中 ,` click ` 事件是用 JavaScript 初始化创建的。处理程序工作方式和点击按钮的方式相同 :
3535
3636``` html run no-beautify
3737<button id =" elem" onclick =" alert('Click!');" >Autoclick</button >
@@ -43,9 +43,9 @@ let event = new Event(event type[, options]);
4343```
4444
4545``` smart header="event.isTrusted"
46- 有一个可以区分 “真实”用户事件和 script 生成事件的方法 。
46+ 有一种方法可以区分 “真实”用户事件和通过脚本生成的事件 。
4747
48- `event.isTrusted` 属性为 `true`,则事件来自真实用户的动作,为 `false` ,则说明事件由脚本生成 。
48+ 对于来自真实用户操作的事件, `event.isTrusted` 属性为 `true`,对于脚本生成的事件,`event.isTrusted` 属性为 `false`。
4949```
5050
5151## 冒泡示例
@@ -58,40 +58,44 @@ let event = new Event(event type[, options]);
5858<h1 id =" elem" >Hello from the script!</h1 >
5959
6060<script >
61- // catch on document...
61+ // 在 document 上捕获 ...
6262 document .addEventListener (" hello" , function (event ) { // (1)
6363 alert (" Hello from " + event .target .tagName ); // Hello from H1
6464 });
6565
66- // ...dispatch on elem!
66+ // ...在 elem 上 dispatch!
6767 let event = new Event (" hello" , {bubbles: true }); // (2)
6868 elem .dispatchEvent (event );
69+
70+ // 在 document 上的处理程序将被激活,并显示消息。
71+
6972 </script >
7073```
7174
75+
7276注意:
7377
74- 1 . 我们应该使用 ` addEventListener ` 定义我们的事件 ,因为 ` on<event> ` 仅存在于内置事件中 ,` document.onhello ` 则无法运行。
78+ 1 . 我们应该对我们的自定义事件使用 ` addEventListener ` ,因为 ` on<event> ` 仅存在于内建事件中 ,` document.onhello ` 则无法运行。
75792 . 必须设置 ` bubbles:true ` ,否则事件不会向上冒泡。
7680
77- 对于内置 ( ` click ` ) 和自定义 ( ` hello ` ) 的事件,冒泡机制是一样的。也有捕获和冒泡阶段 。
81+ 内建事件( ` click ` )和自定义事件( ` hello ` )的冒泡机制相同。自定义事件也有捕获阶段和冒泡阶段 。
7882
79- ## 鼠标事件,键盘事件和其他
83+ ## MouseEvent,KeyboardEvent 及其他
8084
81- 这里有一个在 [ UI Event specification ] ( https://www.w3.org/TR/uievents ) 上的 UI 事件类短列表 :
85+ 这是一个摘自于 [ UI 事件规范 ] ( https://www.w3.org/TR/uievents ) 的一个简短的 UI 事件类列表 :
8286
83- - ` UIEvent ` (UI 事件)
84- - ` FocusEvent ` (焦点事件)
85- - ` MouseEvent ` (鼠标事件)
86- - ` WheelEvent ` (滚轮事件)
87- - ` KeyboardEvent ` (键盘事件)
87+ - ` UIEvent `
88+ - ` FocusEvent `
89+ - ` MouseEvent `
90+ - ` WheelEvent `
91+ - ` KeyboardEvent `
8892- ...
8993
90- 如果我们想要创建这样的事件,我们应该使用它们而不是“新事件” 。例如,` new MouseEvent("click") ` 。
94+ 如果我们想要创建这样的事件,我们应该使用它们而不是 ` new Event ` 。例如,` new MouseEvent("click") ` 。
9195
92- 正确的构造函数允许为该类型的事件指定标准属性 。
96+ 正确的构造器允许为该类型的事件指定标准属性 。
9397
94- 就像鼠标事件 ` clientX/clientY ` 一样:
98+ 就像鼠标事件的 ` clientX/clientY ` 一样:
9599
96100``` js run
97101let event = new MouseEvent (" click" , {
@@ -106,41 +110,40 @@ alert(event.clientX); // 100
106110*/ ! *
107111```
108112
109- 请注意:通用 ` Event ` 构造器不允许这样做。
113+ 请注意:通用的 ` Event ` 构造器不允许这样做。
110114
111115让我们试试:
112116
113117``` js run
114118let event = new Event (" click" , {
115- bubbles: true , // only bubbles and cancelable
116- cancelable: true , // work in the Event constructor
119+ bubbles: true , // 构造器 Event 中只有 bubbles 和 cancelable 可以工作
120+ cancelable: true ,
117121 clientX: 100 ,
118122 clientY: 100
119123});
120124
121125* ! *
122- alert (event .clientX ); // undefined, the unknown property is ignored!
126+ alert (event .clientX ); // undefined,未知的属性被忽略了!
123127*/ ! *
124128```
125129
126- 从技术上讲,我们可以通过在创建后直接分发 ` event.clientX=100 ` 来解决这个问题。所以这是一个方便和遵守规则的问题。浏览器生成的事件总是具有正确的类型 。
130+ 从技术上讲,我们可以通过在创建后直接分配 ` event.clientX=100 ` 来解决这个问题。所以,这是一个方便和遵守规则的问题。浏览器生成的事件始终具有正确的类型 。
127131
128- 不同 UI 事件的所有属性列表在说明书中 ,例如 [ MouseEvent] ( https://www.w3.org/TR/uievents/#mouseevent ) 。
132+ 规范中提供了不同 UI 事件的属性的完整列表 ,例如 [ MouseEvent] ( https://www.w3.org/TR/uievents/#mouseevent ) 。
129133
130134## 自定义事件
131135
132- 对于我们自己的自定义事件,像 ` "hello" ` ,我们应该使用 ` new CustomEvent ` 。从技术上来说,[ CustomEvent] ( https://dom.spec.whatwg.org/#customevent ) 和 ` Event ` 一样。除了一点不同之外。
133-
134- 在第二个参数(对象)中,我们可以在事件中为我们想要传递的任何自定义信息添加一个附加的属性 ` detail ` 。
136+ 对于我们自己的全新事件类型,例如 ` "hello" ` ,我们应该使用 ` new CustomEvent ` 。从技术上讲,[ CustomEvent] ( https://dom.spec.whatwg.org/#customevent ) 和 ` Event ` 一样。除了一点不同。
135137
138+ 在第二个参数(对象)中,我们可以为我们想要与事件一起传递的任何自定义信息添加一个附加的属性 ` detail ` 。
136139
137140例如:
138141
139142``` html run refresh
140143<h1 id =" elem" >Hello for John!</h1 >
141144
142145<script >
143- // additional details come with the event to the handler
146+ // 事件附带给处理程序的其他详细信息
144147 elem .addEventListener (" hello" , function (event ) {
145148 alert (* ! * event .detail .name */ ! * );
146149 });
@@ -149,47 +152,48 @@ alert(event.clientX); // undefined, the unknown property is ignored!
149152* ! *
150153 detail: { name: " John" }
151154*/ ! *
152- });
155+ })) ;
153156 </script >
154157```
155158
156- ` detail` 属性可以有任何数据。从技术上讲,我们可以不用,因为我们可以在创建后将任何属性分配到常规的 ` new Event ` 对象中。但是 ` CustomEvent ` 为它提供了特殊的 ` detail` 字段,以避免与其他事件属性的冲突。
159+ ` detail ` 属性可以有任何数据。从技术上讲,我们可以不用,因为我们可以在创建后将任何属性分配给常规的 ` new Event ` 对象中。但是 ` CustomEvent ` 提供了特殊的 ` detail ` 字段,以避免与其他事件属性的冲突。
157160
158- 事件类告诉一些关于“是什么类型的事件”的信息 ,如果事件是自定义的,那么我们应该使用 ` CustomEvent ` 来明确它是什么。
161+ 此外,事件类描述了它是“什么类型的事件” ,如果事件是自定义的,那么我们应该使用 ` CustomEvent ` 来明确它是什么。
159162
160163## event.preventDefault()
161164
162- 如果 ` cancelable : true ` 被指定,那么我们可以在脚本生成的事件上调用 ` event . preventDefault () ` 。
165+ 许多浏览器事件都有“默认行为”,例如,导航到链接,开始一个选择,等 。
163166
164- 当然,如果事件有一个非标准的名称,那么浏览器就不知道它,而且它也没有“默认浏览器动作” 。
167+ 对于新的,自定义的事件,绝对没有默认的浏览器行为,但是分派(dispatch)此类事件的代码可能有自己的计划,触发该事件之后应该做什么 。
165168
166- 但是事件生成代码可能会在 ` dispatchEvent ` 之后安排一些动作 。
169+ 通过调用 ` event.preventDefault() ` ,事件处理程序可以发出一个信号,指出这些行为应该被取消 。
167170
168- 调用 ` event . preventDefault ( )` 是处理器发送不应该执行这些操作的信号的一种方法 。
171+ 在这种情况下, ` elem.dispatchEvent(event )` 的调用会返回 ` false ` 。那么分派(dispatch)该事件的代码就会知道不应该再继续 。
169172
170- 在这种情况下, ` elem . dispatchEvent ( event ) ` 会返回 ` false ` 。而且事件生成代码知道处理器不应该继续 。
173+ 让我们看一个实际的例子 —— 一只隐藏的兔子(可以是关闭菜单或者其他) 。
171174
172- 例如,在下面的示例中有一个 ` hide () ` 函数。它在元素 ` #rabbit` 上生成 ` " hide" ` 事件。通知所有相关联部分兔子将要隐藏起来了 。
175+ 在下面,你可以看到一个在其上分派了 ` " hide" ` 事件的 ` #rabbit ` 和 ` hide() ` 函数,以使所有感兴趣的各方面都知道这只兔子要隐藏起来 。
173176
174- 由 ` rabbit .addEventListener (' hide' ,... )` 设置的处理器将会知道这些,并且如果需要,可以通过调用 ` event .preventDefault ()` 来阻止该操作。然后兔子就不会隐藏了 :
177+ 任何处理程序都可以使用 ` rabbit.addEventListener('hide',...) ` 来监听该事件,并在需要时使用 ` event.preventDefault() ` 来取消该行为。然后兔子就不会藏起来了 :
175178
176- ` ` ` html run refresh
179+ ``` html run refresh autorun
177180<pre id =" rabbit" >
178181 |\ /|
179182 \|_|/
180183 /. .\
181184 =\_Y_/=
182185 {>o<}
183186</pre >
187+ <button onclick =" hide()" >Hide()</button >
184188
185189<script >
186- // hide() will be called automatically in 2 seconds
190+ // hide() 将在 2 秒后被自动调用
187191 function hide () {
188192 let event = new CustomEvent (" hide" , {
189- cancelable: true // without that flag preventDefault doesn't work
193+ cancelable: true // 没有这个标志, preventDefault 将不起作用
190194 });
191195 if (! rabbit .dispatchEvent (event )) {
192- alert (' the action was prevented by a handler' );
196+ alert (' The action was prevented by a handler' );
193197 } else {
194198 rabbit .hidden = true ;
195199 }
@@ -200,29 +204,25 @@ alert(event.clientX); // undefined, the unknown property is ignored!
200204 event .preventDefault ();
201205 }
202206 });
203-
204- // hide in 2 seconds
205- setTimeout (hide, 2000 );
206-
207207 </script >
208208```
209209
210+ 请注意:该事件必须具有 ` cancelable: true ` 标志,否则 ` event.preventDefault() ` 调用将会被忽略。
210211
211- ## Events-in-events 同步
212+ ## 事件中的事件是同步的
212213
213- 事件通常都是同步处理的 。也就是说:如果浏览器正在处理 ` onclick` ,而且在处理过程中发生了一个新的事件 ,那么它将等待,直到 ` onclick` 处理完成。
214+ 通常事件是被异步处理的 。也就是说:如果浏览器正在处理 ` onclick ` ,在此处理过程中发生了一个新的事件 ,那么它将等待,直到 ` onclick ` 处理完成。
214215
215- 异常情况是一个事件从另一个事件中启动 。
216+ 唯一的例外就是,一个事件是在另一个事件中发起的 。
216217
217- 然后控制器会跳到嵌套事件处理器中,并且(执行完成)之后返回 。
218+ 然后,程序执行的控制流会跳转到嵌套的事件的处理程序,执行完成后返回 。
218219
219- 例如,这里的 ` menu- open` 嵌套事件在 ` onclick` 期间被同步处理:
220+ 例如,这里的嵌套事件 ` menu-open ` 在 ` onclick ` 期间被同步处理:
220221
221- ` ` ` html run
222+ ``` html run autorun
222223<button id =" menu" >Menu (click me)</button >
223224
224225<script >
225- // 1 -> nested -> 2
226226 menu .onclick = function () {
227227 alert (1 );
228228
@@ -234,55 +234,60 @@ alert(event.clientX); // undefined, the unknown property is ignored!
234234 alert (2 );
235235 };
236236
237- document .addEventListener (' menu-open' , () => alert (' nested' ))
237+ document .addEventListener (' menu-open' , () => alert (' nested' ));
238238 </script >
239- ` ` `
239+ ```
240+
241+ 输出顺序为:1 -> nested -> 2。
240242
241- 请注意 ` menu- open` 嵌套事件会冒泡,而且是在 ` document ` 被处理。嵌套事件的传播是在处理返回到外部代码 ( ` onclick` ) 之前就已经全部完成的 。
243+ 请注意,嵌套事件 ` menu-open ` 会完全冒泡,并在 ` document ` 上被处理。嵌套事件的传播(propagation)和处理必须完全完成,然后处理过程才会返回到外部代码( ` onclick ` ) 。
242244
243- 这不仅仅是 ` dispatchEvent` ,还有其他案例。 JavaScript 在事件处理时可以调用导致其他事件的方法 —— 它们也是被同步处理的。
245+ 这不仅与 ` dispatchEvent ` 有关,还有其他情况。事件处理程序中的 JavaScript 可以调用会引发其他事件的方法 —— 它们也是被同步处理的。
244246
245- 如果我们不喜欢 ,可以将 ` dispatchEvent` (或者其他事件触发器调用 )放在 ` onclick` 结束,或者如果不方便,可以将其包装在 ` setTimeout ( ... , 0 ) ` 中:
247+ 如果我们不喜欢它 ,可以将 ` dispatchEvent ` (或者其他触发事件的调用 )放在 ` onclick ` 末尾,或者最好将其包装到零延迟的 ` setTimeout ` 中:
246248
247249``` html run
248250<button id =" menu" >Menu (click me)</button >
249251
250252<script >
251- // 1 -> 2 -> nested
252253 menu .onclick = function () {
253254 alert (1 );
254255
255256 // alert(2)
256257 setTimeout (() => menu .dispatchEvent (new CustomEvent (" menu-open" , {
257258 bubbles: true
258- })), 0 );
259+ })));
259260
260261 alert (2 );
261262 };
262263
263- document .addEventListener (' menu-open' , () => alert (' nested' ))
264+ document .addEventListener (' menu-open' , () => alert (' nested' ));
264265 </script >
265- ` ` `
266+ ```
267+
268+ 现在,` dispatchEvent ` 在当前代码执行完成之后异步运行,包括 ` mouse.onclick ` ,因此,事件处理程序是完全独立的。
269+
270+ 输出顺序变成:1 -> 2 -> nested。
266271
267272## 总结
268273
269- 要生成一个事件 ,我们首先需要创建一个事件对象。
274+ 要从代码生成一个事件 ,我们首先需要创建一个事件对象。
270275
271- 泛型 ` Event (name, options)` 构造器接受任意事件名, ` options` 对象具有两个属性 :
272- - ` bubbles: true ` ,如果事件应该冒泡的话 。
273- - ` cancelable : true ` 则 ` event .preventDefault ()` 应该有效。
276+ 通用的 ` Event(name, options) ` 构造器接受任意事件名称和具有两个属性的 ` options ` 对象 :
277+ - 如果事件应该冒泡,则 ` bubbles: true ` 。
278+ - 如果 ` event.preventDefault() ` 应该有效,则 ` cancelable: true ` 。
274279
275- 其他像 ` MouseEvent ` 、 ` KeyboardEvent ` 这样的原生事件构造器,接受特定于该事件类型的属性 。例如,鼠标事件的 ` clientX` 。
280+ 其他像 ` MouseEvent ` 和 ` KeyboardEvent ` 这样的原生事件的构造器,都接受特定于该事件类型的属性 。例如,鼠标事件的 ` clientX ` 。
276281
277- 对于自定义事件我们应该使用 ` CustomEvent ` 构造器。它有一个名为 ` detail` 的附加选项,我们应该将特定事件的数据指派给它。然后处理器可以以 ` event .detail ` 的形式访问它 。
282+ 对于自定义事件,我们应该使用 ` CustomEvent ` 构造器。它有一个名为 ` detail ` 的附加选项,我们应该将事件特定的数据分配给它。然后,所有处理程序可以以 ` event.detail ` 的形式来访问它 。
278283
279- 尽管技术上有可能产生像 ` click` 或者 ` keydown` 这样的浏览器事件,但我们还是该谨慎使用 。
284+ 尽管技术上有可能生成像 ` click ` 或 ` keydown ` 这样的浏览器事件,但我们还是应谨慎使用 。
280285
281- 我们不应该生成浏览器事件,因为这是运行处理器的一种 hacky 方式。大多数来说 ,这都是一种糟糕的架构。
286+ 我们不应该生成浏览器事件,因为这是运行处理程序的一种怪异( hacky) 方式。大多数时候 ,这都是一种糟糕的架构。
282287
283288可以生成原生事件:
284289
285- - 如果他们不提供其他的交互方式,脏黑客行为可以制作第三方库操作所需的方式 。
286- - 对于自动化测试,要在脚本中“单击按钮”并查看接口是否正确反应 。
290+ - 如果第三方程序库不提供其他交互方式,那么这是使第三方程序库工作所需的一种肮脏手段 。
291+ - 对于自动化测试,要在脚本中“点击按钮”并查看接口是否正确响应 。
287292
288- 使用我们自己的名字来自定义的事件通常是为架构目的产生的,用来指示菜单、滑块、轮播等内部发生什么 。
293+ 使用我们自己的名称的自定义事件通常是出于架构的目的而创建的,以指示发生在菜单(menu),滑块(slider),轮播(carousel)等内部发生了什么 。
0 commit comments