diff --git a/2-ui/2-events/04-default-browser-action/article.md b/2-ui/2-events/04-default-browser-action/article.md index 0e4a1d705b..521c8deaba 100644 --- a/2-ui/2-events/04-default-browser-action/article.md +++ b/2-ui/2-events/04-default-browser-action/article.md @@ -221,7 +221,7 @@ menu.onclick = function(event) { - `mousedown` —— 开始选择(移动鼠标进行选择)。 - 在 `` 上的 `click` —— 选中/取消选中的 `input`。 - `submit` —— 点击 `` 或者在表单字段中按下 `key:Enter` 键会触发该事件,之后浏览器将提交表单。 -- `keydown` —— 按下一个按键可能会导致将字符添加到字段,或者触发其他行为。 +- `keydown` —— 按下一个按键会导致将字符添加到字段,或者触发其他行为。 - `contextmenu` —— 事件发生在鼠标右键单击时,触发的行为是显示浏览器上下文菜单。 - ……还有更多…… diff --git a/2-ui/2-events/05-dispatch-events/article.md b/2-ui/2-events/05-dispatch-events/article.md index eca74ad5d4..94a00743c4 100644 --- a/2-ui/2-events/05-dispatch-events/article.md +++ b/2-ui/2-events/05-dispatch-events/article.md @@ -1,37 +1,37 @@ -# 生成自定义事件 +# 创建自定义事件 -我们不仅可以分发事件,还可以从 JavaScript 中生成事件。 +我们不仅可以分配事件处理程序,还可以从 JavaScript 生成事件。 -自定义事件可以用于创建“图形组件”。例如,菜单组件的根元素可以通过触发 `open`(打开菜单)、`select`(有一项被选中)等事件告诉菜单发生了什么。 +自定义事件可用于创建“图形组件”。例如,我们自己的基于 JavaScript 的菜单的根元素可能会触发 `open`(打开菜单),`select`(有一项被选中)等事件来告诉菜单发生了什么。另一个代码可能会监听事件,并观察菜单发生了什么。 -我们也可以生成一些像 `click`、`mousedown` 此类的内置事件,这些都有利于测试。 +我们不仅可以生成出于自身目的而创建的全新事件,还可以生成例如 `click` 和 `mousedown` 等内建事件。这可能会有助于自动化测试。 ## 事件构造器 -事件会像 DOM 元素类一样形成层次结构。事件的底层是内置的 [Event](http://www.w3.org/TR/dom/#event) 类。 +内建事件类形成一个层次结构,类似于 DOM 元素类。根是内建的 [Event](http://www.w3.org/TR/dom/#event) 类。 我们可以像这样创建 `Event` 对象: ```js -let event = new Event(event type[, options]); +let event = new Event(type[, options]); ``` 参数: -- **event type** —— 可以是任何字符串,比如 `"click"` 或者我们自己喜欢的 `"hey-ho!"`。 +- **type** —— 事件类型,可以是像这样 `"click"` 的字符串,或者我们自己的像这样 `"my-event"` 的参数。 - **options** —— 具有两个可选属性的对象: - - `bubbles: true/false` —— 如果是 `true`,那么事件冒泡。 - - `cancelable: true/false` —— 如果 `true`,那么“默认动作”就会被阻止。之后我们会看到对于自定义事件,这些意味着什么。 + - `bubbles: true/false` —— 如果为 `true`,那么事件会冒泡。 + - `cancelable: true/false` —— 如果为 `true`,那么“默认行为”就会被阻止。稍后我们会看到对于自定义事件,它意味着什么。 - 默认情况下,它们都是 false:`{bubbles: false, cancelable: false}`。 + 默认情况下,以上两者都为 false:`{bubbles: false, cancelable: false}`。 ## dispatchEvent -事件对象被创建后,我们应该调用 `elem.dispatchEvent(event)` 在元素上“运行”它。 +事件对象被创建后,我们应该使用 `elem.dispatchEvent(event)` 调用在元素上“运行”它。 -然后处理器对其作出反应,就好像它是一个正常的内置事件。如果事件是使用 `bubbles` 标志创建的,那么它就会冒泡。 +然后,处理程序会对它做出反应,就好像它是一个常规的浏览器事件一样。如果事件是用 `bubbles` 标志创建的,那么它会冒泡。 -在下面示例中,`click` 事件是用 JavaScript 初始化生成的。处理器执行效果和单击按钮的效果一样: +在下面这个示例中,`click` 事件是用 JavaScript 初始化创建的。处理程序工作方式和点击按钮的方式相同: ```html run no-beautify @@ -43,9 +43,9 @@ let event = new Event(event type[, options]); ``` ```smart header="event.isTrusted" -有一个可以区分 “真实”用户事件和 script 生成事件的方法。 +有一种方法可以区分“真实”用户事件和通过脚本生成的事件。 -`event.isTrusted` 属性为 `true`,则事件来自真实用户的动作,为 `false` ,则说明事件由脚本生成。 +对于来自真实用户操作的事件,`event.isTrusted` 属性为 `true`,对于脚本生成的事件,`event.isTrusted` 属性为 `false`。 ``` ## 冒泡示例 @@ -58,40 +58,44 @@ let event = new Event(event type[, options]);
|\ /|
\|_|/
@@ -181,15 +184,16 @@ alert(event.clientX); // undefined, the unknown property is ignored!
=\_Y_/=
{>o<}
+
```
+请注意:该事件必须具有 `cancelable: true` 标志,否则 `event.preventDefault()` 调用将会被忽略。
-## Events-in-events 同步
+## 事件中的事件是同步的
-事件通常都是同步处理的。也就是说:如果浏览器正在处理 `onclick`,而且在处理过程中发生了一个新的事件,那么它将等待,直到 `onclick` 处理完成。
+通常事件是被异步处理的。也就是说:如果浏览器正在处理 `onclick`,在此处理过程中发生了一个新的事件,那么它将等待,直到 `onclick` 处理完成。
-异常情况是一个事件从另一个事件中启动。
+唯一的例外就是,一个事件是在另一个事件中发起的。
-然后控制器会跳到嵌套事件处理器中,并且(执行完成)之后返回。
+然后,程序执行的控制流会跳转到嵌套的事件的处理程序,执行完成后返回。
-例如,这里的 `menu-open` 嵌套事件在 `onclick` 期间被同步处理:
+例如,这里的嵌套事件 `menu-open` 在 `onclick` 期间被同步处理:
-```html run
+```html run autorun
-```
+```
+
+输出顺序为:1 -> nested -> 2。
-请注意 `menu-open` 嵌套事件会冒泡,而且是在 `document` 被处理。嵌套事件的传播是在处理返回到外部代码 (`onclick`) 之前就已经全部完成的。
+请注意,嵌套事件 `menu-open` 会完全冒泡,并在 `document` 上被处理。嵌套事件的传播(propagation)和处理必须完全完成,然后处理过程才会返回到外部代码(`onclick`)。
-这不仅仅是 `dispatchEvent`,还有其他案例。JavaScript 在事件处理时可以调用导致其他事件的方法 —— 它们也是被同步处理的。
+这不仅与 `dispatchEvent` 有关,还有其他情况。事件处理程序中的 JavaScript 可以调用会引发其他事件的方法 —— 它们也是被同步处理的。
-如果我们不喜欢,可以将 `dispatchEvent`(或者其他事件触发器调用)放在 `onclick` 结束,或者如果不方便,可以将其包装在 `setTimeout(...,0)` 中:
+如果我们不喜欢它,可以将 `dispatchEvent`(或者其他触发事件的调用)放在 `onclick` 末尾,或者最好将其包装到零延迟的 `setTimeout` 中:
```html run
-```
+```
+
+现在,`dispatchEvent` 在当前代码执行完成之后异步运行,包括 `mouse.onclick`,因此,事件处理程序是完全独立的。
+
+输出顺序变成:1 -> 2 -> nested。
## 总结
-要生成一个事件,我们首先需要创建一个事件对象。
+要从代码生成一个事件,我们首先需要创建一个事件对象。
-泛型 `Event(name, options)` 构造器接受任意事件名,`options` 对象具有两个属性:
- - `bubbles: true` ,如果事件应该冒泡的话。
- - `cancelable: true` 则 `event.preventDefault()` 应该有效。
+通用的 `Event(name, options)` 构造器接受任意事件名称和具有两个属性的 `options` 对象:
+- 如果事件应该冒泡,则 `bubbles: true`。
+- 如果 `event.preventDefault()` 应该有效,则 `cancelable: true`。
-其他像 `MouseEvent`、`KeyboardEvent` 这样的原生事件构造器,接受特定于该事件类型的属性。例如,鼠标事件的 `clientX`。
+其他像 `MouseEvent` 和 `KeyboardEvent` 这样的原生事件的构造器,都接受特定于该事件类型的属性。例如,鼠标事件的 `clientX`。
-对于自定义事件我们应该使用 `CustomEvent` 构造器。它有一个名为 `detail` 的附加选项,我们应该将特定事件的数据指派给它。然后处理器可以以 `event.detail` 的形式访问它。
+对于自定义事件,我们应该使用 `CustomEvent` 构造器。它有一个名为 `detail` 的附加选项,我们应该将事件特定的数据分配给它。然后,所有处理程序可以以 `event.detail` 的形式来访问它。
-尽管技术上有可能产生像 `click` 或者 `keydown` 这样的浏览器事件,但我们还是该谨慎使用。
+尽管技术上有可能生成像 `click` 或 `keydown` 这样的浏览器事件,但我们还是应谨慎使用。
-我们不应该生成浏览器事件,因为这是运行处理器的一种 hacky 方式。大多数来说,这都是一种糟糕的架构。
+我们不应该生成浏览器事件,因为这是运行处理程序的一种怪异(hacky)方式。大多数时候,这都是一种糟糕的架构。
可以生成原生事件:
-- 如果他们不提供其他的交互方式,脏黑客行为可以制作第三方库操作所需的方式。
-- 对于自动化测试,要在脚本中“单击按钮”并查看接口是否正确反应。
+- 如果第三方程序库不提供其他交互方式,那么这是使第三方程序库工作所需的一种肮脏手段。
+- 对于自动化测试,要在脚本中“点击按钮”并查看接口是否正确响应。
-使用我们自己的名字来自定义的事件通常是为架构目的产生的,用来指示菜单、滑块、轮播等内部发生什么。
+使用我们自己的名称的自定义事件通常是出于架构的目的而创建的,以指示发生在菜单(menu),滑块(slider),轮播(carousel)等内部发生了什么。