diff --git a/1-js/09-classes/06-instanceof/article.md b/1-js/09-classes/06-instanceof/article.md index 93352dbafd..b6ad87f37d 100644 --- a/1-js/09-classes/06-instanceof/article.md +++ b/1-js/09-classes/06-instanceof/article.md @@ -1,4 +1,4 @@ -# 类型检查:"instanceof" +# 类检查:"instanceof" `instanceof` 操作符用于检查一个对象是否属于某个特定的 class。同时,它还考虑了继承。 @@ -215,4 +215,4 @@ alert( {}.toString.call(new XMLHttpRequest()) ); // [object XMLHttpRequest] 正如我们所看到的,从技术上讲,`{}.toString` 是一种“更高级的” `typeof`。 -当我们使用多层类结构,并想要对该类进行检查,同时还要考虑继承时,这种场景下 `instanceof` 运算符确实很出色。 +当我们使用类的层次结构(hierarchy),并想要对该类进行检查,同时还要考虑继承时,这种场景下 `instanceof` 操作符确实很出色。 diff --git a/1-js/10-error-handling/2-custom-errors/article.md b/1-js/10-error-handling/2-custom-errors/article.md index 7e20268ab9..2385998d28 100644 --- a/1-js/10-error-handling/2-custom-errors/article.md +++ b/1-js/10-error-handling/2-custom-errors/article.md @@ -6,7 +6,7 @@ JavaScript 允许将 `throw` 与任何参数一起使用,所以从技术上讲,我们自定义的 error 不需要继承从 `Error` 中继承。但是,如果我们继承,那么就可以使用 `obj instanceof Error` 来识别 error 对象。因此,最好继承它。 -随着虽开发的应用程序的增长,我们自己的 error 自然会形成形成一个层次结构。例如,`HttpTimeoutError` 可能继承自 `HttpError`,等等。 +随着虽开发的应用程序的增长,我们自己的 error 自然会形成形成一个层次结构(hierarchy)。例如,`HttpTimeoutError` 可能继承自 `HttpError`,等等。 ## 扩展 Error diff --git a/2-ui/1-document/04-searching-elements-dom/article.md b/2-ui/1-document/04-searching-elements-dom/article.md index 2bb5f65297..970aa223f9 100644 --- a/2-ui/1-document/04-searching-elements-dom/article.md +++ b/2-ui/1-document/04-searching-elements-dom/article.md @@ -103,7 +103,7 @@ 这个方法确实功能强大,因为可以使用任何 CSS 选择器。 ```smart header="也可以使用伪类" -CSS 选择器的伪类,例如 `:hover` 和 `:active` 也都是被支持的。例如,`document.querySelectorAll(':hover')` 将会返回指针现在已经结束的元素的集合(按嵌套顺序:从最外层 `` 到嵌套最多的元素)。 +CSS 选择器的伪类,例如 `:hover` 和 `:active` 也都是被支持的。例如,`document.querySelectorAll(':hover')` 将会返回鼠标指针现在已经结束的元素的集合(按嵌套顺序:从最外层 `` 到嵌套最多的元素)。 ``` ## querySelector [#querySelector] diff --git a/2-ui/1-document/09-size-and-scroll/article.md b/2-ui/1-document/09-size-and-scroll/article.md index e74c306ac1..6ee93a020d 100644 --- a/2-ui/1-document/09-size-and-scroll/article.md +++ b/2-ui/1-document/09-size-and-scroll/article.md @@ -53,7 +53,7 @@ JavaScript 中有许多属性可让我们读取有关元素宽度、高度和其 ## offsetParent,offsetLeft/Top -这些属性很少使用,但它们仍然是“最外层”的几何属性,所以我们将从它们开始。 +这些属性很少使用,但它们仍然是“最外面”的几何属性,所以我们将从它们开始。 `offsetParent` 是最接近的祖先(ancestor),在浏览器渲染期间,它被用于计算坐标。 diff --git a/2-ui/1-document/10-size-and-scroll-window/article.md b/2-ui/1-document/10-size-and-scroll-window/article.md index 18260d865a..e30c005e09 100644 --- a/2-ui/1-document/10-size-and-scroll-window/article.md +++ b/2-ui/1-document/10-size-and-scroll-window/article.md @@ -2,7 +2,7 @@ 我们如何找到浏览器窗口(window)的宽度和高度呢?我们如何获得文档(document)的包括滚动部分在内的完整宽度和高度呢?我们如何使用 JavaScript 滚动页面? -对于大多数此类请求,我们可以使用与 `` 标签相对应的根文档元素 `document.documentElement`。但是还有很多其他方法,这些方法和特性非常重要,值得我们考虑。 +对于大多数此类请求,我们可以使用与 `` 标签相对应的根文档元素 `document.documentElement`。但是还有很多其他方法,这些方法和特性非常重要,值得我们考虑。 ## 窗口的 width/height @@ -33,7 +33,7 @@ alert( document.documentElement.clientWidth ); // 减去滚动条宽度后的窗 ```` ```warn header="`DOCTYPE` 很重要" -请注意:当 HTML 中没有 `` 时,顶层几何属性的工作方式可能就会有所不同。可能会出现一些稀奇古怪的情况。 +请注意:当 HTML 中没有 `` 时,顶层级(top-level)几何属性的工作方式可能就会有所不同。可能会出现一些稀奇古怪的情况。 在现代 HTML 中,我们始终都应该写 `DOCTYPE`。 ``` diff --git a/2-ui/2-events/01-introduction-browser-events/04-move-ball-field/task.md b/2-ui/2-events/01-introduction-browser-events/04-move-ball-field/task.md index de9dbd377a..5936c2ad31 100644 --- a/2-ui/2-events/01-introduction-browser-events/04-move-ball-field/task.md +++ b/2-ui/2-events/01-introduction-browser-events/04-move-ball-field/task.md @@ -10,7 +10,7 @@ importance: 5 要求: -- 球的中心应该恰好在点击时指针位置的下方(如果在球不越过球场边缘的情况下,能实现的话)。 +- 球的中心应该恰好在点击时鼠标指针位置的下方(如果在球不越过球场边缘的情况下,能实现的话)。 - 最好添加一些 CSS 动画。 - 球不能越过场地边界。 - 页面滚动时,不会有任何中断。 diff --git a/2-ui/2-events/02-bubbling-and-capturing/article.md b/2-ui/2-events/02-bubbling-and-capturing/article.md index bdee065251..c63ad89c3b 100644 --- a/2-ui/2-events/02-bubbling-and-capturing/article.md +++ b/2-ui/2-events/02-bubbling-and-capturing/article.md @@ -210,7 +210,7 @@ elem.addEventListener("click", e => alert(2)); 每个处理程序都可以访问 `event` 对象的属性: -- `event.target` —— 引发事件的最深层的元素。 +- `event.target` —— 引发事件的层级最深的元素。 - `event.currentTarget`(=`this`)—— 处理事件的当前元素(具有处理程序的元素) - `event.eventPhase` —— 当前阶段(capturing=1,target=2,bubbling=3)。 @@ -220,6 +220,6 @@ elem.addEventListener("click", e => alert(2)); 在现实世界中,当事故发生时,当地警方会首先做出反应。他们最了解发生这件事的地方。然后,如果需要,上级主管部门再进行处理。 -事件处理程序也是如此。在特定元素上设置处理程序的代码,了解有关该元素最详尽的信息。特定于 `` 的处理程序可能恰好适合于该 ``,这个处理程序知道关于该元素的所有信息。所以该处理程序应该首先获得机会。然后,它的直接父元素也了解相关上下文,但了解的内容会少一些,以此类推,直到处理一般性概念并最后运行的最顶层的元素为止。 +事件处理程序也是如此。在特定元素上设置处理程序的代码,了解有关该元素最详尽的信息。特定于 `` 的处理程序可能恰好适合于该 ``,这个处理程序知道关于该元素的所有信息。所以该处理程序应该首先获得机会。然后,它的直接父元素也了解相关上下文,但了解的内容会少一些,以此类推,直到处理一般性概念并最后运行的最顶部的元素为止。 冒泡和捕获为“事件委托”奠定了基础 —— 一种非常强大的事件处理模式,我们将在下一章中进行研究。 diff --git a/2-ui/2-events/03-event-delegation/4-behavior-tooltip/task.md b/2-ui/2-events/03-event-delegation/4-behavior-tooltip/task.md index ff8518b58a..7b10d2a368 100644 --- a/2-ui/2-events/03-event-delegation/4-behavior-tooltip/task.md +++ b/2-ui/2-events/03-event-delegation/4-behavior-tooltip/task.md @@ -29,7 +29,7 @@ importance: 5 在这里你将需要两个事件: - `mouseover` 当鼠标指针出现在元素上方时触发。 -- `mouseout` 当指针离开元素时触发。 +- `mouseout` 当鼠标指针离开元素时触发。 请使用事件委托:在 `document` 上设置两个处理程序,以跟踪带有 `data-tooltip` 的元素中的所有 "over" 和 "out",并从那里管理工具提示。 diff --git a/2-ui/2-events/05-dispatch-events/article.md b/2-ui/2-events/05-dispatch-events/article.md index 94a00743c4..9ec16d6650 100644 --- a/2-ui/2-events/05-dispatch-events/article.md +++ b/2-ui/2-events/05-dispatch-events/article.md @@ -8,7 +8,7 @@ ## 事件构造器 -内建事件类形成一个层次结构,类似于 DOM 元素类。根是内建的 [Event](http://www.w3.org/TR/dom/#event) 类。 +内建事件类形成一个层次结构(hierarchy),类似于 DOM 元素类。根是内建的 [Event](http://www.w3.org/TR/dom/#event) 类。 我们可以像这样创建 `Event` 对象: diff --git a/2-ui/3-event-details/1-mouse-events-basics/article.md b/2-ui/3-event-details/1-mouse-events-basics/article.md index 9ae7921936..59a010b4a7 100644 --- a/2-ui/3-event-details/1-mouse-events-basics/article.md +++ b/2-ui/3-event-details/1-mouse-events-basics/article.md @@ -194,4 +194,4 @@ Before... `mousedown` 的默认浏览器操作是文本选择,如果它对界面不利,则应避免它。 -在下一章中,我们将看到有关指针移动后的事件,以及如何跟踪其下元素变化的更多详细信息。 +在下一章中,我们将看到有关鼠标指针移动后的事件,以及如何跟踪其下元素变化的更多详细信息。 diff --git a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/article.md b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/article.md index 63525dc709..fe3c6371f7 100644 --- a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/article.md +++ b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/article.md @@ -52,7 +52,7 @@ 另一方面,我们应该记住,鼠标指针并不会“访问”所有元素。它可以“跳过”一些元素。 -特别是,指针可能会从窗口外跳到页面的中间。在这种情况下,`relatedTarget` 为 `null`,因为它是从石头缝里蹦出来的(nowhere): +特别是,鼠标指针可能会从窗口外跳到页面的中间。在这种情况下,`relatedTarget` 为 `null`,因为它是从石头缝里蹦出来的(nowhere): ![](mouseover-mouseout-from-outside.svg) @@ -61,18 +61,18 @@ 它的 HTML 有两个嵌套的元素:`
` 在 `
` 内部。如果将鼠标快速移动到它们上,则可能只有 `
` 或者只有 `
` 触发事件,或者根本没有事件触发。 -还可以将指针移动到 `
` 中,然后将其快速向下移动过其父级元素。如果移动速度足够快,则父元素就会被忽略。鼠标会越过父元素而不会引起其注意。 +还可以将鼠标指针移动到 `
` 中,然后将其快速向下移动过其父级元素。如果移动速度足够快,则父元素就会被忽略。鼠标会越过父元素而不会引起其注意。 [codetabs height=360 src="mouseoverout-fast"] ``` ```smart header="如果 `mouseover` 被触发了,则必须有 `mouseout`" -在鼠标快速移动的情况下,中间元素可能会被忽略,但是我们可以肯定一件事:如果指针“正式地”进入了一个元素(生成了 `mouseover` 事件),那么一旦它离开,我们就会得到 `mouseout`。 +在鼠标快速移动的情况下,中间元素可能会被忽略,但是我们可以肯定一件事:如果鼠标指针“正式地”进入了一个元素(生成了 `mouseover` 事件),那么一旦它离开,我们就会得到 `mouseout`。 ``` ## 当移动到一个子元素时 mouseout -`mouseout` 的一个重要功能 —— 当指针从元素移动到其后代时触发,例如在下面的这个 HTML 中,从 `#parent` 到 `#child`: +`mouseout` 的一个重要功能 —— 当鼠标指针从元素移动到其后代时触发,例如在下面的这个 HTML 中,从 `#parent` 到 `#child`: ```html
@@ -80,7 +80,7 @@
``` -如果我们在 `#parent` 上,然后将指针更深入地移入 `#child`,但是在 `#parent` 上会得到 `mouseout`! +如果我们在 `#parent` 上,然后将鼠标指针更深入地移入 `#child`,但是在 `#parent` 上会得到 `mouseout`! ![](mouseover-to-child.svg) @@ -106,7 +106,7 @@ [codetabs height=360 src="mouseoverout-child"] ``` -如上例所示,当指针从 `#parent` 元素移动到 `#child` 时,会在父元素上触发两个处理程序:`mouseout` 和 `mouseover`: +如上例所示,当鼠标指针从 `#parent` 元素移动到 `#child` 时,会在父元素上触发两个处理程序:`mouseout` 和 `mouseover`: ```js parent.onmouseout = function(event) { @@ -119,9 +119,9 @@ parent.onmouseover = function(event) { **如果我们不检查处理程序中的 `event.target`,那么似乎鼠标指针离开了 `#parent` 元素,然后立即回到了它上面。** -但是事实并非如此!指针仍然位于父元素上,它只是更深入地移入了子元素。 +但是事实并非如此!鼠标指针仍然位于父元素上,它只是更深入地移入了子元素。 -如果离开父元素时有一些行为(action),例如一个动画在 `parent.onmouseout` 中运行,当指针深入 `#parent` 时,我们并不希望发生这种行为。 +如果离开父元素时有一些行为(action),例如一个动画在 `parent.onmouseout` 中运行,当鼠标指针深入 `#parent` 时,我们并不希望发生这种行为。 为了避免它,我们可以在处理程序中检查 `relatedTarget`,如果鼠标指针仍在元素内,则忽略此类事件。 @@ -138,14 +138,14 @@ parent.onmouseover = function(event) { 这些事件非常简单。 -当指针进入一个元素时 —— 会触发 `mouseenter`。而指针在元素或其后代中的确切位置无关紧要。 +当鼠标指针进入一个元素时 —— 会触发 `mouseenter`。而鼠标指针在元素或其后代中的确切位置无关紧要。 当鼠标指针离开该元素时,事件 `mouseleave` 才会触发。 ```online -这个例子和上面的例子相似,但是现在最顶层的元素有 `mouseenter/mouseleave` 而不是 `mouseover/mouseout`。 +这个例子和上面的例子相似,但是现在最顶部的元素有 `mouseenter/mouseleave` 而不是 `mouseover/mouseout`。 -正如你所看到的,唯一生成的事件是与将指针移入或移出顶部元素有关的事件。当指针进入 child 并返回时,什么也没发生。在后代之间的移动会被忽略。 +正如你所看到的,唯一生成的事件是与将鼠标指针移入或移出顶部元素有关的事件。当鼠标指针进入 child 并返回时,什么也没发生。在后代之间的移动会被忽略。 [codetabs height=340 src="mouseleave"] ``` @@ -158,14 +158,14 @@ parent.onmouseover = function(event) { 通常的解决方案是 —— 在 `` 中设置处理程序,并在那里处理事件。但 `mouseenter/leave` 不会冒泡。因此,如果类似的事件发生在 `
` 上,那么只有 `` 上的处理程序才能捕获到它。 -`` 上的 `mouseenter/leave` 的处理程序仅在指针进入/离开整个表格时才会触发。无法获取有关其内部移动的任何信息。 +`
` 上的 `mouseenter/leave` 的处理程序仅在鼠标指针进入/离开整个表格时才会触发。无法获取有关其内部移动的任何信息。 因此,让我们使用 `mouseover/mouseout`。 -让我们从突出显示鼠标指针下的元素的简单处理程序开始: +让我们从高亮显示鼠标指针下的元素的简单处理程序开始: ```js -// 突出显示鼠标指针下的元素 +// 高亮显示鼠标指针下的元素 table.onmouseover = function(event) { let target = event.target; target.style.background = 'pink'; @@ -178,7 +178,7 @@ table.onmouseout = function(event) { ``` ```online -现在它们已经激活了。当鼠标在下面这个表格的各个元素上移动时,当前位于鼠标指针下的元素会被突出显示: +现在它们已经激活了。当鼠标在下面这个表格的各个元素上移动时,当前位于鼠标指针下的元素会被高亮显示: [codetabs height=480 src="mouseenter-mouseleave-delegation"] ``` @@ -197,14 +197,14 @@ table.onmouseout = function(event) { 再次,重要的功能是: 1. 它使用事件委托来处理表格中任何 `
` 的进入/离开。因此,它依赖于 `mouseover/out` 而不是 `mouseenter/leave`,`mouseenter/leave` 不会冒泡,因此也不允许事件委托。 -2. 额外的事件,例如在 `` 的后代之间移动都会被过滤掉,因此 `onEnter/Leave` 仅在指针进入/离开 `` 整体时才会运行。 +2. 额外的事件,例如在 `` 的后代之间移动都会被过滤掉,因此 `onEnter/Leave` 仅在鼠标指针进入/离开 `` 整体时才会运行。 ```online 这是带有所有详细信息的完整示例: [codetabs height=460 src="mouseenter-mouseleave-delegation-2"] -尝试将鼠标指针移入和移出表格单元格及其内部。快还是慢都没关系。与前面的示例不同,只有 `` 被作为一个整体突出显示。 +尝试将鼠标指针移入和移出表格单元格及其内部。快还是慢都没关系。与前面的示例不同,只有 `` 被作为一个整体高亮显示。 ``` ## 总结 diff --git a/2-ui/3-event-details/4-mouse-drag-and-drop/1-slider/solution.md b/2-ui/3-event-details/4-mouse-drag-and-drop/1-slider/solution.md index 5fe481443a..45b1f0666e 100644 --- a/2-ui/3-event-details/4-mouse-drag-and-drop/1-slider/solution.md +++ b/2-ui/3-event-details/4-mouse-drag-and-drop/1-slider/solution.md @@ -1,4 +1,5 @@ +正如我们从 HTML/CSS 中所看到的,滑动条就是一个带有彩色北京的 `
`,其中包含一个滑块 —— 另一个具有 `position:relative` 的 `
`。 -我们这里有一个水平拖放。 +为了对滑块进行定位,我们使用 `position:relative` 来提供相对于其父元素的坐标,在这儿它比 `position:absolute` 更方便。 -我们使用 `position:relative` 和滚动条的相对坐标的 thumb 来定位元素。这里比 `position:absolute` 更方便。 +然后我们通过限制宽度来实现仅水平方向的拖放。 diff --git a/2-ui/3-event-details/4-mouse-drag-and-drop/1-slider/task.md b/2-ui/3-event-details/4-mouse-drag-and-drop/1-slider/task.md index ea07890107..4d851278e6 100644 --- a/2-ui/3-event-details/4-mouse-drag-and-drop/1-slider/task.md +++ b/2-ui/3-event-details/4-mouse-drag-and-drop/1-slider/task.md @@ -2,15 +2,15 @@ importance: 5 --- -# 滚动条 +# 滑动条 -创建一个滚动条 +创建一个滑动条(slider): [iframe src="solution" height=60 border=1] -用鼠标拖动蓝色 thumb 并移动它。 +用鼠标拖动蓝色的滑块(thumb)并移动它。 重要的细节: -- 在按住鼠标进行拖动时,鼠标可能会越过滚动条的上下边界,滑块应该还在继续移动(对用户来说,这非常方便)。 -- 如果鼠标在移动到左边或右边的速度非常快,那么 thumb 应该完全停在边缘。 +- 当鼠标按钮被按下时,在滑动过程中,鼠标指针可能会移动到滑块的上方或下方。此时滑块仍会继续移动(方便用户)。 +- 如果鼠标非常快地向左边或者向右边移动,那么滑块应该恰好停在边缘。 diff --git a/2-ui/3-event-details/4-mouse-drag-and-drop/2-drag-heroes/solution.md b/2-ui/3-event-details/4-mouse-drag-and-drop/2-drag-heroes/solution.md index d8a5e78dfb..3d9a5e9370 100644 --- a/2-ui/3-event-details/4-mouse-drag-and-drop/2-drag-heroes/solution.md +++ b/2-ui/3-event-details/4-mouse-drag-and-drop/2-drag-heroes/solution.md @@ -1,5 +1,5 @@ -我们应该把属性切换回 `position:fixed` 来拖动它,它让坐标管理更简单。最后,我们应该使用 `position:absolute`。 +要拖动元素,我们可以使用 `position:fixed`,它使坐标更易于管理。最后,我们应该将其切换回 `position:absolute`,以使元素放置到文档中。 -然后,当坐标位于窗口顶部/底部时,我们使用 `window.scrollTo` 滚动它。 +当坐标位于窗口顶端/底端时,我们使用 `window.scrollTo` 来滚动它。 -注释中有更多关于代码的细节。 +更多细节请见代码注释。 diff --git a/2-ui/3-event-details/4-mouse-drag-and-drop/2-drag-heroes/solution.view/index.html b/2-ui/3-event-details/4-mouse-drag-and-drop/2-drag-heroes/solution.view/index.html index d79ef30a4e..63c762feb0 100644 --- a/2-ui/3-event-details/4-mouse-drag-and-drop/2-drag-heroes/solution.view/index.html +++ b/2-ui/3-event-details/4-mouse-drag-and-drop/2-drag-heroes/solution.view/index.html @@ -8,17 +8,17 @@ -

Place superheroes around the soccer field.

+

将超级英雄放置在足球场周围。

-

Superheroes and the ball are elements with the class "draggable". Make them really draggable.

+

超级英雄和球都是带有 "draggable" 类的元素。使它们真的可拖动(draggable)。

-

Important: limit dragging by the window. If a draggable reaches window top or bottom, then the page should scroll to let us drag it further.

+

重要:通过窗口限制拖动。如果可拖动的元素被拖到窗口的顶端或末端,则页面应该滚动以让我们进一步拖动它。

-

If your screen is big enough to fit the whole document -- make the window smaller to get vertical scrolling, so that you could test it.

+

如果你的屏幕足够大,能够把整个文档都显示出来 —— 那么请缩小窗口以进行垂直滚动,以便对此进行测试。

-

In this task it's enough to handle vertical scrolling. There's no horizontal scrolling usually, and it's handled the similar way if needed.

+

在此任务中,处理垂直滚动就够了。通常没有水平滚动,并且在需要时可以采用类似的方式进行处理。

-

And one more thing: heroes may never leave the page. If they reach the edge of the document, no dragging outside of it.

+

此外:英雄永远都不会离开页面。如果它们到达了文档的边缘,它们不会被拖动到文档外。

diff --git a/2-ui/3-event-details/4-mouse-drag-and-drop/2-drag-heroes/solution.view/soccer.js b/2-ui/3-event-details/4-mouse-drag-and-drop/2-drag-heroes/solution.view/soccer.js index 10ae2eeed0..89455e6653 100644 --- a/2-ui/3-event-details/4-mouse-drag-and-drop/2-drag-heroes/solution.view/soccer.js +++ b/2-ui/3-event-details/4-mouse-drag-and-drop/2-drag-heroes/solution.view/soccer.js @@ -24,9 +24,9 @@ document.addEventListener('mousedown', function(event) { moveAt(event.clientX, event.clientY); } - // on drag start: - // remember the initial shift - // move the element position:fixed and a direct child of body + // 在拖动开始时: + // 记住初始的移位 + // 将元素设置为 position:fixed,并将此元素移动到作为 body 的直接子元素 function startDrag(element, clientX, clientY) { if(isDragging) { return; @@ -45,7 +45,7 @@ document.addEventListener('mousedown', function(event) { moveAt(clientX, clientY); }; - // switch to absolute coordinates at the end, to fix the element in the document + // 在最后,转换到绝对(absolute)坐标,以将元素固定在文档中 function finishDrag() { if(!isDragging) { return; @@ -61,49 +61,49 @@ document.addEventListener('mousedown', function(event) { } function moveAt(clientX, clientY) { - // new window-relative coordinates + // 新的窗口相对坐标 let newX = clientX - shiftX; let newY = clientY - shiftY; - // check if the new coordinates are below the bottom window edge + // 检查新坐标是否在底部窗口边缘以下 let newBottom = newY + dragElement.offsetHeight; // new bottom - // below the window? let's scroll the page + // 在窗口边缘以下?让我们滚动此页面 if (newBottom > document.documentElement.clientHeight) { - // window-relative coordinate of document end + // 文档末端的窗口相对坐标 let docBottom = document.documentElement.getBoundingClientRect().bottom; - // scroll the document down by 10px has a problem - // it can scroll beyond the end of the document + // 将文档向下滚动 10px 有一个问题 + // 它可以滚动到文档末尾之后 // Math.min(how much left to the end, 10) let scrollY = Math.min(docBottom - newBottom, 10); - // calculations are imprecise, there may be rounding errors that lead to scrolling up - // that should be impossible, fix that here + // 计算是不精确的,可能会有舍入误差导致页面向上滚动 + // 这是不应该出现,我们在这儿解决它 if (scrollY < 0) scrollY = 0; window.scrollBy(0, scrollY); - // a swift mouse move make put the cursor beyond the document end - // if that happens - - // limit the new Y by the maximally possible (right at the bottom of the document) + // 快速移动鼠标将指针移至文档末端的外面 + // 如果发生这种情况 —— + // 使用最大的可能距离来限制 newY(就是文档末端到顶端的距离) newY = Math.min(newY, document.documentElement.clientHeight - dragElement.offsetHeight); } - // check if the new coordinates are above the top window edge (similar logic) + // 检查新坐标是否在顶部窗口边缘上方(类似的逻辑) if (newY < 0) { // scroll up let scrollY = Math.min(-newY, 10); - if (scrollY < 0) scrollY = 0; // check precision errors + if (scrollY < 0) scrollY = 0; // 检查精度损失 window.scrollBy(0, -scrollY); - // a swift mouse move can put the cursor beyond the document start - newY = Math.max(newY, 0); // newY may not be below 0 + // 快速移动鼠标可以使指针超出文档的顶端 + newY = Math.max(newY, 0); // newY 不得小于 0 } - // limit the new X within the window boundaries - // there's no scroll here so it's simple + // 将 newX 限制在窗口范围内 + // 这里没有滚动,所以它很简单 if (newX < 0) newX = 0; if (newX > document.documentElement.clientWidth - dragElement.offsetWidth) { newX = document.documentElement.clientWidth - dragElement.offsetWidth; diff --git a/2-ui/3-event-details/4-mouse-drag-and-drop/2-drag-heroes/source.view/index.html b/2-ui/3-event-details/4-mouse-drag-and-drop/2-drag-heroes/source.view/index.html index d79ef30a4e..63c762feb0 100644 --- a/2-ui/3-event-details/4-mouse-drag-and-drop/2-drag-heroes/source.view/index.html +++ b/2-ui/3-event-details/4-mouse-drag-and-drop/2-drag-heroes/source.view/index.html @@ -8,17 +8,17 @@ -

Place superheroes around the soccer field.

+

将超级英雄放置在足球场周围。

-

Superheroes and the ball are elements with the class "draggable". Make them really draggable.

+

超级英雄和球都是带有 "draggable" 类的元素。使它们真的可拖动(draggable)。

-

Important: limit dragging by the window. If a draggable reaches window top or bottom, then the page should scroll to let us drag it further.

+

重要:通过窗口限制拖动。如果可拖动的元素被拖到窗口的顶端或末端,则页面应该滚动以让我们进一步拖动它。

-

If your screen is big enough to fit the whole document -- make the window smaller to get vertical scrolling, so that you could test it.

+

如果你的屏幕足够大,能够把整个文档都显示出来 —— 那么请缩小窗口以进行垂直滚动,以便对此进行测试。

-

In this task it's enough to handle vertical scrolling. There's no horizontal scrolling usually, and it's handled the similar way if needed.

+

在此任务中,处理垂直滚动就够了。通常没有水平滚动,并且在需要时可以采用类似的方式进行处理。

-

And one more thing: heroes may never leave the page. If they reach the edge of the document, no dragging outside of it.

+

此外:英雄永远都不会离开页面。如果它们到达了文档的边缘,它们不会被拖动到文档外。

diff --git a/2-ui/3-event-details/4-mouse-drag-and-drop/2-drag-heroes/task.md b/2-ui/3-event-details/4-mouse-drag-and-drop/2-drag-heroes/task.md index c6d7717279..a76443e6ac 100644 --- a/2-ui/3-event-details/4-mouse-drag-and-drop/2-drag-heroes/task.md +++ b/2-ui/3-event-details/4-mouse-drag-and-drop/2-drag-heroes/task.md @@ -2,19 +2,19 @@ importance: 5 --- -# 在领域周围拖动 superhero +# 将超级英雄放置在足球场周围 -这个任务可以帮助你检查对拖放和 DOM 一些方面的理解程度。 +这个任务可以帮助你检查你对拖放和 DOM 的一些方面的理解程度。 -使所有元素都具有类 `draggable` —— 可拖。就像章节里的球。 +使所有元素都具有类 `draggable` —— 可拖动。就像本章中的球一样。 要求: -- 使用事件委托来跟踪拖动的开始:`document` 用于 `mousedown` 的单个处理器。 -- 如果将元素拖动到窗口的顶部/底部 —— 页面就会允许进一步的向上/向下滚动。 -- 没有水平滚动。 -- 即使鼠标迅速移动,可拖动的元素也不应离开窗口。 +- 使用事件委托来跟踪拖动的开始:一个在 `document` 上的用于 `mousedown` 的处理程序。 +- 如果元素被拖动到了窗口的顶端/末端 —— 页面会向上/向下滚动以允许进一步的拖动。 +- 没有水平滚动(这使本任务更简单,但添加水平滚动也很简单)。 +- 即使在快速移动鼠标后,可拖动元素或该元素的部分也绝不应该离开窗口。 -这个示例太大了,不适合放在这里,但这里有相应的链接。 +这个示例太大了,不适合放在这里,所以在下面给出了示例链接。 [demo src="solution"] diff --git a/2-ui/3-event-details/4-mouse-drag-and-drop/article.md b/2-ui/3-event-details/4-mouse-drag-and-drop/article.md index 65622e8256..509126dff4 100644 --- a/2-ui/3-event-details/4-mouse-drag-and-drop/article.md +++ b/2-ui/3-event-details/4-mouse-drag-and-drop/article.md @@ -1,42 +1,41 @@ -# 拖放鼠标事件 +# 鼠标拖放事件 -拖放是一个很好的界面解决方案。从复制和移动(参考文件管理)到排序(放入购物车),拖放是一种简洁明了的方法。 +拖放(Drag'n'Drop)是一个很赞的界面解决方案。取某件东西并将其拖放是执行许多东西的一种简单明了的方式,从复制和移动文档(如在文件管理器中)到订购(将物品放入购物车)。 -在现代 HTML 标准中,有一个[拖动事件的部分](https://html.spec.whatwg.org/multipage/interaction.html#dnd)。 +在现代 HTML 标准中有一个 [关于拖放的部分](https://html.spec.whatwg.org/multipage/interaction.html#dnd),其中包含了例如 `dragstart` 和 `dragend` 等特殊事件。 -这很有趣,因为它们允许轻松地解决一些简单的任务,而且允许处理“外部”文件拖放到浏览器中的事件。因此我们可以在 OS 文件管理中获取文件,并将其拖动到浏览器窗口。然后 JavaScript 获取对其内容的访问权限。 +这些事件很有用,因为它们使我们能够轻松地解决简单的任务。例如,使我们能够处理将“外部”文件拖放到浏览器中的操作,因此我们可以在 OS 文件管理器中获取文件,并将其拖放到浏览器窗口中,从而使 JavaScript 可以访问其内容。 -但是本地的拖动事件总是有局限性。比如,我们可以把拖动范围限制在某个区域内。而且我们也可以把它变成 "horizontal" 或 "vertical"。还有其他的拖放任务无法通过使用 API 实现。 +但是,原声的拖放事件也有其局限性。例如,我们无法将拖放限制在某个区域内。并且,我们无法将拖放变成“水平”或“垂直”拖放。还有其他一些使用该 API 无法完成的拖放任务。此外,移动设备基本都不支持此事件。 -在这里,我们将看到如何使用鼠标事件实现拖放。并不难。 +因此,在这里我们将看到,如何使用鼠标事件来实现拖放。 ## 拖放算法 -拖放基础算法就像这样: +基础的拖放算法如下所示: -1. 在可拖动元素上捕获 `mousedown` 事件。 -2. 准备要移动的元素(可能创建它的副本或其他任何东西)。 -3. 然后在 `mousemove` 上,通过改变 `left/top` 和 `position:absolute` 来移动它。 -4. 在 `mouseup`(释放按钮)中 —— 执行所有完成拖放相关的动作。 +1. 在 `mousedown` 上 —— 根据需要准备要移动的元素(也许创建它的一个副本)。 +2. 然后在 `mousemove` 上,通过更改 `left/top` 和 `position:absolute` 来移动它。 +3. 在 `mouseup` 上 —— 执行与完成的拖放相关的所有行为。 -这些是基础。我们可以对其进行拓展,例如,当鼠标在可拖动元素上悬停时,高亮这个元素。 +这些是基础。稍后我们可以扩展它,例如,当鼠标悬停在元素上方时,高亮显示 "droppable"(可用于放置到)的元素。 -这是拖放球的算法: +下面是拖放一个球的算法: ```js -ball.onmousedown = function(event) { // (1) 启动进程 +ball.onmousedown = function(event) { // (1) 启动处理 - // (2) 准备移动:确保 absolute,以及用 z-index 确保在顶部 + // (2) 准备移动:确保 absolute,并通过设置 z-index 以确保球在顶部 ball.style.position = 'absolute'; ball.style.zIndex = 1000; - // 将它从当前父亲中直接移到 body 中 - // 确保它的位置是相对于 body 的 + // 将其从当前父元素中直接移动到 body 中 + // 以使其定位是相对于 body 的 document.body.append(ball); - // ...将绝对定位的球放在光标下 + // ...并将绝对定位的球放在鼠标指针下方 moveAt(event.pageX, event.pageY); - // 球中心在 (pageX, pageY) 坐标上 + // 现在球的中心在 (pageX, pageY) 坐标上 function moveAt(pageX, pageY) { ball.style.left = pageX - ball.offsetWidth / 2 + 'px'; ball.style.top = pageY - ball.offsetHeight / 2 + 'px'; @@ -46,10 +45,10 @@ ball.onmousedown = function(event) { // (1) 启动进程 moveAt(event.pageX, event.pageY); } - // (3) 在 mousemove 事件中移动球 + // (3) 在 mousemove 事件上移动球 document.addEventListener('mousemove', onMouseMove); - // (4) 释放球,移除不需要的处理器 + // (4) 放下球,并移除不需要的处理程序 ball.onmouseup = function() { document.removeEventListener('mousemove', onMouseMove); ball.onmouseup = null; @@ -58,19 +57,19 @@ ball.onmousedown = function(event) { // (1) 启动进程 }; ``` -如果我们运行代码,我们会发现一些奇怪的事情。在拖放的一开始,球会 "forks":我们开始拖动它的 "clone"。 +如果我们运行这段代码,我们会发现一些奇怪的事情。在拖放的一开始,球“分叉”了:我们开始拖动它的“克隆”。 ```online -这是一个动作实例: +这是一个正在运行中的示例: [iframe src="ball" height=230] -尝试拖放鼠标,你会看到奇怪的行为。 +尝试拖放鼠标,你会看到这种奇怪的行为。 ``` -这是因为浏览器有自己拖放图像功能和其他一些自动运行可能与我们的产生冲突的元素。 +这是因为浏览器有自己的对图片和一些其他元素的拖放处理,会在我们拖放时自动运行,这与我们的拖放处理产生了冲突。 -如果禁用: +禁用它: ```js ball.ondragstart = function() { @@ -78,40 +77,42 @@ ball.ondragstart = function() { }; ``` -现在一切都会好起来的。 +现在一切都正常了。 ```online -动作: +这是一个正在运行中的示例: [iframe src="ball2" height=230] ``` -另一个重要的方面是 —— 我们在 `document` 上跟踪 `mousemove`,而不是在 `ball` 上。第一眼看,鼠标似乎总是在球的上方,我们可以在上面放 `mousemove`。 +另一个重要的方面是 —— 我们在 `document` 上跟踪 `mousemove`,而不是在 `ball` 上。乍一看,鼠标似乎总是在球的上方,我们可以将 `mousemove` 放在球上。 -正如我们记得的那样,`mousemove` 会经常被触发,但不会针对每个像素都如此。因此在快速移动之后,光标可以从文档中心的某个地方(甚至是窗口外)从球上跳出来。 +但正如我们所记得的那样,`mousemove` 会经常被触发,但不会针对每个像素都如此。因此,在快速移动鼠标后,鼠标指针可能会从球上跳转至文档中间的某个位置(甚至跳转至窗口外)。 -因此为了捕获它,我们应该监听 `document`。 +因此,我们应该监听 `document` 以捕获它。 ## 修正定位 -在上述例子中,球总是以指针为中心的: +在上述示例中,球在移动时,球的中心始终位于鼠标指针下方: ```js ball.style.left = pageX - ball.offsetWidth / 2 + 'px'; ball.style.top = pageY - ball.offsetHeight / 2 + 'px'; ``` -不错,但这存在副作用。我们可以在球的任何地方使用 `mousedown` 来开始拖放。如果在边缘那么做,那么球就会突然“跳”到以指针为中心的位置。 +不错,但这存在副作用。要启动拖放,我们可以在球上的任意位置 `mousedown`。但是,如果从球的边缘“抓住”球,那么球会突然“跳转”以使球的中心位于鼠标指针下方。 -如果我们保持元素相对指针的初始位移,情况会更好。 +如果我们能够保持元素相对于鼠标指针的初始偏移,那就更好了。 -例如,我们从球的边缘处开始拖动,那么光标在拖动时应该保持在边缘。 +例如,我们按住球的边缘处开始拖动,那么在拖动时,鼠标指针应该保持在一开始所按住的边缘位置上。 ![](ball_shift.svg) -1. 当访问者按下按钮(`mousedown`)时 —— 我们可以使用变量 `shiftX/shiftY` 来记住光标到球左上角的距离。我们应该在拖动时保持这样的距离。 +让我们更新一下我们的算法: - 我们可以减去坐标来获取位移: +1. 当访问者按下按钮(`mousedown`)时 —— 我们可以在变量 `shiftX/shiftY` 中记住鼠标指针到球左上角的距离。我们应该在拖动时保持这个距离。 + + 我们可以通过坐标相减来获取这个偏移: ```js // onmousedown @@ -119,18 +120,16 @@ ball.style.top = pageY - ball.offsetHeight / 2 + 'px'; let shiftY = event.clientY - ball.getBoundingClientRect().top; ``` - 请注意,在 JavaScript 中没有获取文档坐标的方法,因此我们在这里使用相对于窗口的坐标。 - -2. 然后,在拖动球时,我们将球放置在相对于指针移动的位置上,就像这样: +2. 然后,在拖动球时,我们将鼠标指针相对于球的这个偏移也考虑在内,像这样: ```js // onmousemove - // ball has position:absoute + // 球具有 position:absoute ball.style.left = event.pageX - *!*shiftX*/!* + 'px'; ball.style.top = event.pageY - *!*shiftY*/!* + 'px'; ``` -具有更好定位的最终代码: +能够更好地进行定位的最终代码: ```js ball.onmousedown = function(event) { @@ -146,7 +145,8 @@ ball.onmousedown = function(event) { moveAt(event.pageX, event.pageY); - // 球中心在 (pageX, pageY) 坐标上 + // 移动现在位于坐标 (pageX, pageY) 上的球 + // 将初始的偏移考虑在内 function moveAt(pageX, pageY) { ball.style.left = pageX - *!*shiftX*/!* + 'px'; ball.style.top = pageY - *!*shiftY*/!* + 'px'; @@ -156,10 +156,10 @@ ball.onmousedown = function(event) { moveAt(event.pageX, event.pageY); } - // (3) 用 mousemove 移动球 + // 在 mousemove 事件上移动球 document.addEventListener('mousemove', onMouseMove); - // (4) 释放球,移除不需要的处理器 + // 放下球,并移除不需要的处理程序 ball.onmouseup = function() { document.removeEventListener('mousemove', onMouseMove); ball.onmouseup = null; @@ -178,25 +178,27 @@ In action (inside `