Skip to content

Update some chapters to [Jul 17, 2020] Part-6 #795

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions 2-ui/1-document/01-browser-environment/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

JavaScript 语言最初是为 Web 浏览器创建的。此后,它已经发展成为一种具有多种用途和平台的语言。

平台可以是一个浏览器,一个 Web 服务器,或其他 **主机(host)**,甚至是咖啡机。它们每个都提供了特定于平台的功能。JavaScript 规范将其称为 **主机环境**。
平台可以是一个浏览器,一个 Web 服务器,或其他 **主机(host)**,甚至可以是一个“智能”咖啡机,如果它能运行 JavaScript 的话。它们每个都提供了特定于平台的功能。JavaScript 规范将其称为 **主机环境**。

主机环境提供了自己的对象和语言核心以外的函数。Web 浏览器提供了一种控制网页的方法。Node.JS 提供了服务器端功能,等等。

Expand Down Expand Up @@ -49,9 +49,7 @@ document.body.style.background = "red";
setTimeout(() => document.body.style.background = "", 1000);
```

在这里,我们使用了 `document.body.style`,但还有很多很多其他的东西。规范中有属性和方法的详细描述:

- **DOM Living Standard**:<https://dom.spec.whatwg.org>
在这里,我们使用了 `document.body.style`,但还有很多很多其他的东西。规范中有属性和方法的详细描述:[DOM Living Standard](https://dom.spec.whatwg.org)。

```smart header="DOM 不仅仅用于浏览器"
DOM 规范解释了文档的结构,并提供了操作文档的对象。有的非浏览器设备也使用 DOM。
Expand All @@ -60,9 +58,9 @@ DOM 规范解释了文档的结构,并提供了操作文档的对象。有的
```

```smart header="用于样式的 CSSOM"
CSS 规则和样式表的结构与 HTML 不同。有一个单独的规范 [CSS Object Model (CSSOM)](https://www.w3.org/TR/cssom-1/),它解释了如何将 CSS 表示为对象,以及如何读写它们。
There's also a separate specification, [CSS Object Model (CSSOM)](https://www.w3.org/TR/cssom-1/) for CSS rules and stylesheets, that explains how they are represented as objects, and how to read and write them.

当我们修改文档的样式规则时,CSSOM 与 DOM 是一起使用的。但实际上,很少需要 CSSOM,因为通常 CSS 规则是静态的。我们很少需要从 JavaScript 中添加/删除 CSS 规则,但你要知道这是可行的。
当我们修改文档的样式规则时,CSSOM 与 DOM 是一起使用的。但实际上,很少需要 CSSOM,因为 we rarely need to modify CSS rules from JavaScript (usually we just add/remove CSS classes, not modify their CSS rules), but that's also possible.
```

## 浏览器对象模型(BOM)
Expand Down
37 changes: 25 additions & 12 deletions 2-ui/1-document/07-modifying-document/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ DOM 修改是创建“实时”页面的关键。
*/!*
```

这是一个 HTML 示例。现在,让我们使用 JavaScript 创建一个相同的 `div`(假设样式在 HTML 或外部 CSS 文件中)。
这是一个 HTML 示例。现在,让我们使用 JavaScript 创建一个相同的 `div`(假设样式已经在 HTML/CSS 文件中)。

## 创建一个元素

Expand All @@ -48,21 +48,28 @@ DOM 修改是创建“实时”页面的关键。
let textNode = document.createTextNode('Here I am');
```

Most of the time we need to create element nodes, such as the `div` for the message.

### 创建一条消息

在我们的例子中,消息是一个带有 `alert` 类和 HTML 的 `div`:
Creating the message div takes 3 steps:

```js
// 1. Create <div> element
let div = document.createElement('div');

// 2. Set its class to "alert"
div.className = "alert";

// 3. Fill it with the content
div.innerHTML = "<strong>Hi there!</strong> You've read an important message.";
```

我们创建了元素,但到目前为止,它还只是在变量中。我们无法在页面上看到该元素,因为它还不是文档的一部分
我们已经创建了该元素。但到目前为止,它还只是在一个名为 `div` 的变量中,尚未在页面中。所以我们无法在页面上看到它

## 插入方法

为了让 `div` 显示出来,我们需要将其插入到 `document` 中的某处。例如,在 `document.body` 中。
为了让 `div` 显示出来,我们需要将其插入到 `document` 中的某处。例如,into `<body>` element, referenced by `document.body`.

对此有一个特殊的方法 `append`:`document.body.append(div)`。

Expand Down Expand Up @@ -90,14 +97,20 @@ div.innerHTML = "<strong>Hi there!</strong> You've read an important message.";
</script>
```

下面这些方法提供了更多的插入方式:
Here we called `append` on `document.body`, but we can call `append` method on any other element, to put another element into it. For instance, we can append something to `<div>` by calling `div.append(anotherElement)`.

- `node.append(...nodes or strings)` — 在 `node` 末尾插入节点或字符串,
- `node.prepend(...nodes or strings)` — 在 `node` 开头插入节点或字符串,
- `node.before(...nodes or strings)` — 在 `node` 前面插入节点或字符串,
- `node.after(...nodes or strings)` — 在 `node` 后面插入节点或字符串,
Here are more insertion methods, they specify different places where to insert:

- `node.append(...nodes or strings)` — 在 `node` **末尾** 插入节点或字符串,
- `node.prepend(...nodes or strings)` — 在 `node` **开头** 插入节点或字符串,
- `node.before(...nodes or strings)` — 在 `node` **前面** 插入节点或字符串,
- `node.after(...nodes or strings)` — 在 `node` **后面** 插入节点或字符串,
- `node.replaceWith(...nodes or strings)` — 将 `node` 替换为给定的节点或字符串。

Arguments of these methods are an arbitrary list of DOM nodes to insert, or text strings (that become text nodes automatically).

Let's see them in action.

下面是使用这些方法将列表项添加到列表中,以及将文本添加到列表前面和后面的示例:

```html autorun
Expand Down Expand Up @@ -139,7 +152,7 @@ before
after
```

这些方法可以在单个调用中插入多个节点列表和文本片段。
如上所述,这些方法可以在单个调用中插入多个节点列表和文本片段。

例如,在这里插入了一个字符串和一个元素:

Expand All @@ -150,7 +163,7 @@ after
</script>
```

所有内容都被“作为文本”插入。
Please note: the text is inserted "as text", not "as HTML", with proper escaping of characters such as `<`, `>`.

所以,最终的 HTML 为:

Expand All @@ -166,7 +179,7 @@ after

所以,这些方法只能用来插入 DOM 节点或文本片段。

但是,如果我们想在所有标签和内容正常工作的情况下,将这些内容“作为 HTML” 插入到 HTML 中,就像 `elem.innerHTML` 方法一样,那有什么方法可以实现吗?
But what if we'd like to insert an HTML string "as html", with all tags and stuff working, in the same manner as `elem.innerHTML` does it?

## insertAdjacentHTML/Text/Element

Expand Down
2 changes: 1 addition & 1 deletion 2-ui/1-document/09-size-and-scroll/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ element.style.height = `${element.scrollHeight}px`;
<div onclick="this.scrollTop+=10" style="cursor:pointer;border:1px solid black;width:100px;height:80px;overflow:auto">Click<br>Me<br>1<br>2<br>3<br>4<br>5<br>6<br>7<br>8<br>9</div>
```

将 `scrollTop` 设置为 `0` 或 `Infinity` 将会使元素滚动到顶部/底部。
将 `scrollTop` 设置为 `0` 或一个大的值,例如 `1e9`,将会使元素滚动到顶部/底部。
````

## 不要从 CSS 中获取 width/height
Expand Down
2 changes: 2 additions & 0 deletions 2-ui/1-document/11-coordinates/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,8 @@ function getCoords(elem) {

return {
top: box.top + window.pageYOffset,
right: box.right + window.pageXOffset,
bottom: box.bottom + window.pageYOffset,
left: box.left + window.pageXOffset
};
}
Expand Down
75 changes: 37 additions & 38 deletions 2-ui/2-events/01-introduction-browser-events/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@
- `mousedown` / `mouseup` —— 当在元素上按下/释放鼠标按钮时。
- `mousemove` —— 当鼠标移动时。

**键盘事件**:
- `keydown` and `keyup` -- when a keyboard key is pressed and released.

**表单(form)元素事件**:
- `submit` —— 当访问者提交了一个 `<form>` 时。
- `focus` —— 当访问者聚焦于一个元素时,例如聚焦于一个 `<input>`。

**键盘事件**:
- `keydown` 和 `keyup` —— 当访问者按下然后松开按键时。

**Document 事件**:
- `DOMContentLoaded` —— 当 HTML 的加载和处理均完成,DOM 被完全构建完成时。

Expand Down Expand Up @@ -87,8 +87,6 @@ HTML 特性不是编写大量代码的好位置,因此我们最好创建一个

因此,这种方法实际上与前一种方法相同。

**处理程序总是在 DOM 属性中:HTML 特性只是初始化它的方法之一**。

这两段代码工作相同:

1. 只有 HTML:
Expand All @@ -109,6 +107,8 @@ HTML 特性不是编写大量代码的好位置,因此我们最好创建一个
</script>
```

In the first example, the HTML attribute is used to initialize the `button.onclick`, while in the second example -- the script, that's all the difference.

**因为这里只有一个 `onclick` 属性,所以我们无法分配更多事件处理程序。**

在下面这个示例中,我们使用 JavaScript 添加了一个处理程序,覆盖了现有的处理程序:
Expand All @@ -124,16 +124,6 @@ HTML 特性不是编写大量代码的好位置,因此我们最好创建一个
</script>
```

顺便说一下,我们可以直接将现有的函数指定为处理程序:

```js
function sayThanks() {
alert('Thanks!');
}

elem.onclick = sayThanks;
```

要移除一个处理程序 —— 赋值 `elem.onclick = null`。

## 访问元素:this
Expand All @@ -150,7 +140,17 @@ elem.onclick = sayThanks;

如果你刚开始写事件 —— 请注意一些细微之处。

**函数应该被以 `sayThanks` 的形式进行非配,而不是 `sayThanks()`**。
We can set an existing function as a handler:

```js
function sayThanks() {
alert('Thanks!');
}

elem.onclick = sayThanks;
```

But be careful: the function should be assigned as `sayThanks`, not `sayThanks()`.

```js
// 正确
Expand All @@ -160,29 +160,25 @@ button.onclick = sayThanks;
button.onclick = sayThanks();
```

如果我们添加了括号 `sayThanks()` —— 这是一个函数调用。所以,最后一行代码实际上获得的是函数执行的 **结果**,即 `undefined`(因为这个函数没有返回值)。此代码不会工作。
如果我们添加了括号,那么 `sayThanks()` 就变成了一个函数调用。所以,最后一行代码实际上获得的是函数执行的 **结果**,即 `undefined`(因为这个函数没有返回值)。此代码不会工作。

……但在标记(markup)中,我们确实需要括号:

```html
<input type="button" id="button" onclick="sayThanks()">
```

这个区别很容易解释。当浏览器读取 HTML 特性(attribute)时,浏览器将会使用 **特性中的内容** 创建一个处理程序:`sayThanks()`
这个区别很容易解释。当浏览器读取 HTML 特性(attribute)时,浏览器将会使用 **特性中的内容** 创建一个处理程序。

所以,标记(markup)会生成下面这个属性:
```js
button.onclick = function() {
*!*
sayThanks(); // 特性中的内容
sayThanks(); // <-- 特性(attribute)中的内容变到了这里
*/!*
};
```

**使用函数,而不是字符串。**

`elem.onclick = "alert(1)"` 也可以执行。它能执行是出于兼容性,但强烈建议不要使用这种方式。

**不要对处理程序使用 `setAttribute`。**

这样的调用会失效:
Expand All @@ -201,7 +197,7 @@ document.body.setAttribute('onclick', function() { alert(1) });

上述分配处理程序的方式的根本问题是 —— 我们不能为一个事件分配多个处理程序。

例如,在我们点击了一个按钮时,我们代码中的一部分想要高亮显示这个按钮,另一部分则想要显示一条消息。
假设,在我们点击了一个按钮时,我们代码中的一部分想要高亮显示这个按钮,另一部分则想要显示一条消息。

我们想为此事件分配两个处理程序。但是,新的 DOM 属性将覆盖现有的 DOM 属性:

Expand Down Expand Up @@ -229,8 +225,7 @@ element.addEventListener(event, handler[, options]);
: 具有以下属性的附加可选对象:
- `once`:如果为 `true`,那么会在被触发后自动删除监听器。
- `capture`:事件处理的阶段,我们稍后将在 <info:bubbling-and-capturing> 一章中介绍。由于历史原因,`options` 也可以是 `false/true`,它与 `{capture: false/true}` 相同。
- `passive`:如果为 `true`,那么处理程序将不会 `preventDefault()`,我们稍后将在 <info:default-browser-action> 一章中介绍。

- `passive`:如果为 `true`,那么处理程序将不会调用 `preventDefault()`,我们稍后将在 <info:default-browser-action> 一章中介绍。

要移除处理程序,可以使用 `removeEventListener`:

Expand All @@ -249,7 +244,7 @@ elem.addEventListener( "click" , () => alert('Thanks!'));
elem.removeEventListener( "click", () => alert('Thanks!'));
```

处理程序不会被移除,因为 `removeEventListener` 获取了另一个函数 —— 使用相同的代码,但这并不起作用。
处理程序不会被移除,因为 `removeEventListener` 获取了另一个函数 —— 使用相同的代码,但这并不起作用,因为它是一个不同的函数对象

下面是正确方法:

Expand Down Expand Up @@ -291,31 +286,33 @@ input.removeEventListener("click", handler);
正如我们在上面这个例子中所看到的,我们可以 **同时** 使用 DOM 属性和 `addEventListener` 来设置处理程序。但通常我们只使用其中一种方式。

````warn header="对于某些事件,只能通过 `addEventListener` 设置处理程序"
有些事件无法通过 DOM 属性进行分配。必须使用 `addEventListener`。
有些事件无法通过 DOM 属性进行分配。只能使用 `addEventListener`。

例如,`DOMContentLoaded` 事件,该事件在文档加载完成并且 DOM 构建完成时触发。

```js
// 永远不会运行
document.onDOMContentLoaded = function() {
alert("DOM built"); // 永远不会运行
alert("DOM built");
};
```

```js
// 这种方式可以运行
document.addEventListener("DOMContentLoaded", function() {
alert("DOM built"); // 这种方式可以运行
alert("DOM built");
});
```
所以 `addEventListener` 更通用。虽然这样的事件是特例而不是规则。
````

## 事件对象

为了正确处理事件,我们需要更深入地了解发生了什么。不仅仅是 "click" 或 "keypress",还包括鼠标指针的坐标是什么?按下了哪个键?等等。
为了正确处理事件,我们需要更深入地了解发生了什么。不仅仅是 "click" 或 "keydown",还包括鼠标指针的坐标是什么?按下了哪个键?等等。

当事件发生时,浏览器会创建一个 **`event` 对象**,将详细信息放入其中,并将其作为参数传递给处理程序。

下面是一个从 `event` 对象获取鼠标坐标的示例
下面是一个从 `event` 对象获取鼠标指针的坐标的示例

```html run
<input type="button" value="Click me" id="elem">
Expand All @@ -338,11 +335,11 @@ document.addEventListener("DOMContentLoaded", function() {
: 处理事件的元素。这与 `this` 相同,除非处理程序是一个箭头函数,或者它的 `this` 被绑定到了其他东西上,之后我们就可以从 `event.currentTarget` 获取元素了。

`event.clientX / event.clientY`
: 鼠标事件的指针的窗口相对坐标
: 指针事件(pointer event)的指针的窗口相对坐标

还有很多属性。它们取决于事件类型,因此,稍后我们将详细讨论不同事件,那时我们再对其进行详细研究。
还有很多属性。其中很多都取决于事件类型:键盘事件具有一组属性,指针事件具有另一组属性,稍后我们将详细讨论不同事件,那时我们再对其进行详细研究。

````smart header="也可以从 HTML 中访问 `event` 对象"
````smart header="`event` 对象在 HTML 处理程序中也可用"
如果我们在 HTML 中分配了一个处理程序,那么我们也可以使用 `event` 对象,像这样:

```html autorun height=60
Expand All @@ -364,15 +361,17 @@ document.addEventListener("DOMContentLoaded", function() {
<button id="elem">Click me</button>

<script>
elem.addEventListener('click', {
let obj = {
handleEvent(event) {
alert(event.type + " at " + event.currentTarget);
}
});
};

elem.addEventListener('click', obj);
</script>
```

正如我们所看到的,当 `addEventListener` 接收一个对象作为处理程序时,在事件发生时,它就会调用 `object.handleEvent(event)` 来处理事件。
正如我们所看到的,当 `addEventListener` 接收一个对象作为处理程序时,在事件发生时,它就会调用 `obj.handleEvent(event)` 来处理事件。

我们也可以对此使用一个类:

Expand Down
4 changes: 2 additions & 2 deletions 2-ui/2-events/03-event-delegation/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@ table.onclick = function(event) {

解释:
1. `elem.closest(selector)` 方法返回与 `selector` 匹配的最近的祖先。在我们的例子中,我们从源元素开始向上寻找 `<td>`。
2. 如果 `event.target` 不在任何 `<td>` 中,那么调用将返回 `null`,我们不需要做任何事情
3. 在嵌套的表格的情况下,`event.target` 可能是位于当前表格之外的 `<td>`。因此我们需要检查这是否是 **我们的表格中的** `<td>`。
2. 如果 `event.target` 不在任何 `<td>` 中,那么调用将立即返回,因为这里没有什么事儿可做
3. 对于嵌套的表格,`event.target` 可能是一个 `<td>`,但位于当前表格之外。因此我们需要检查它是否是 **我们的表格中的** `<td>`。
4. 如果是的话,就高亮显示它。

最终,我们得到了一个快速、高效的用于高亮显示的代码,该代码与表格中的 `<td>` 的数量无关。
Expand Down
Loading