From f5c3f37455bae0a783d083b6426dfca3b6b428c6 Mon Sep 17 00:00:00 2001 From: wizardforcel <562826179@qq.com> Date: Sat, 12 May 2018 12:05:55 +0800 Subject: [PATCH] 15. --- 15.md | 236 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 119 insertions(+), 117 deletions(-) diff --git a/15.md b/15.md index 402bb1e..80c7836 100644 --- a/15.md +++ b/15.md @@ -6,7 +6,7 @@ 有些程序需要处理用户的直接输入,比如鼠标和键盘动作。这种输入方式不是组织整齐的数据结构 - 它是一次一个地,实时地出现的,并且期望程序在发生时作出响应。 -### 14.1 事件处理器 +## 事件处理器 想象一下,有一个接口,若想知道键盘上是否有一个键是否被按下,唯一的方法是读取那个按键的当前状态。为了能够响应按键动作,你需要不断读取键盘状态,以在按键被释放之前捕捉到按下状态。这种方法在执行时间密集计算时非常危险,因为你可能错过按键事件。 @@ -27,7 +27,7 @@ `window`绑定指向浏览器提供的内置对象。 它代表包含文档的浏览器窗口。 调用它的`addEventListener`方法注册第二个参数,以便在第一个参数描述的事件发生时调用它。 -### 14.2 事件与DOM节点 +## 事件与DOM节点 每个浏览器事件处理器被注册在上下文中。在为整个窗口注册处理器之前,我们在`window`对象上调用了`addEventListener`。 这种方法也可以在 DOM 元素和一些其他类型的对象上找到。 仅当事件发生在其注册对象的上下文中时,才调用事件监听器。 @@ -64,7 +64,7 @@ 赋予`removeEventListener`的函数必须是赋予`addEventListener`的完全相同的函数值。 因此,要注销一个处理其,您需要为该函数提供一个名称(在本例中为`once`),以便能够将相同的函数值传递给这两个方法。 -### 14.3 事件对象 +## 事件对象 虽然目前为止我们忽略了它,事件处理器函数作为对象传递:事件(Event)对象。这个对象持有事件的额外信息。例如,如果我们想知道哪个鼠标按键被按下,我们可以查看事件对象的which属性。 @@ -86,7 +86,7 @@ 存储在各种类型事件对象中的信息是有差别的。随后本章将会讨论许多类型的事件。对象的type属性一般持有一个字符串,表示事件(例如“click”和“mousedown”)。 -### 14.4 传播 +## 传播 对于大多数事件类型,在具有子节点的节点上注册的处理器,也将接收发生在子节点中的事件。若点击一个段落中的按钮,段落的事件处理器也会收到点击事件。 @@ -128,7 +128,7 @@ ``` -### 14.5 默认动作 +## 默认动作 大多数事件都有与其关联的默认动作。若点击链接,就会跳转到链接目标。若点击向下的箭头,浏览器会向下翻页。若右击鼠标,可以得到一个上下文菜单等。 @@ -151,7 +151,7 @@ 在有些浏览器中,你完全无法拦截某些事件。比如在Chrome中,关闭键盘快捷键(CTRL-W或COMMAND-W)无法由JavaScript处理。 -### 14.6 按键事件 +## 按键事件 当按下键盘上的按键时,浏览器会触发“keydown”事件。当松开按键时,会触发“keyup”事件。 @@ -198,7 +198,7 @@ 目前有两种广泛使用的方式,用于指向屏幕上的东西:鼠标(包括类似鼠标的设备,如触摸板和轨迹球)和触摸屏。 它们产生不同类型的事件。 -### 鼠标点击 +## 鼠标点击 点击鼠标按钮会触发一系列事件。“mousedown”事件和“mouseup”事件类似于“keydown”和“keyup”事件,当鼠标按钮按下或释放时触发。当事件发生时,由鼠标指针下方的DOM节点触发事件。 @@ -234,7 +234,7 @@ ``` -### 鼠标移动 +## 鼠标移动 每次鼠标移动时都会触发“mousemove”事件。该事件可用于跟踪鼠标位置。当实现某些形式的鼠标拖拽功能时,该事件非常有用。 @@ -276,67 +276,86 @@ 请注意,这些代码的顺序与`button`使用的顺序不同,中键位于右键之前。 如前所述,一致性并不是浏览器编程接口的强项。 -### 触摸事件 +## 触摸事件 我们使用的图形浏览器的风格,是考虑到鼠标界面的情况下而设计的,那个时候触摸屏非常罕见。 为了使网络在早期的触摸屏手机上“工作”,在某种程度上,这些设备的浏览器假装触摸事件是鼠标事件。 如果你点击你的屏幕,你会得到`'mousedown'`,`'mouseup'`和`'click'`事件。 +但是这种错觉不是很健壮。 触摸屏与鼠标的工作方式不同:它没有多个按钮,当手指不在屏幕上时不能跟踪手指(来模拟`"mousemove"`),并且允许多个手指同时在屏幕上。 -函数isInside会沿着指定节点父节点链接寻找节点,直到到达文档顶部(当node为null时),或找到了目标父节点为止。 +鼠标事件只涵盖了简单情况下的触摸交互 - 如果您为按钮添加`"click"`处理器,触摸用户仍然可以使用它。 但是像上一个示例中的可调整大小的栏在触摸屏上不起作用。 -我们可以使用CSS的伪选择子(pseudoselector):hover来更轻松地实现同样的效果。但当浮动效果更加复杂(不只是改变目标节点效果)时,你必须使用mouseover和mouseout事件这种技巧。 +触摸交互触发了特定的事件类型。 当手指开始触摸屏幕时,您会看到`'touchstart'`事件。 当它在触摸中移动时,触发`"touchmove"`事件。 最后,当它停止触摸屏幕时,您会看到`"touchend"`事件。 +由于许多触摸屏可以同时检测多个手指,这些事件没有与其关联的一组坐标。 相反,它们的事件对象拥有`touches`属性,它拥有一个类数组对象,每个对象都有自己的`clientX`,`clientY`,`pageX`和`pageY`属性。 + +你可以这样,在每个触摸手指周围显示红色圆圈。 ```html -

Hover over this paragraph.

+

Touch this page

+ ``` -### 14.9 滚动事件 +您经常希望在触摸事件处理器中调用`preventDefault`,来覆盖浏览器的默认行为(可能包括在滑动时滚动页面),并防止触发鼠标事件,您也可能拥有它的处理器。 + +## 滚动事件 每当元素滚动时,会触发scroll事件。该事件用处极多,比如知道用户当前查看的元素(禁用用户视线以外的动画,或向邪恶的指挥部发送监视报告),或展示一些滚动的迹象(通过高亮表格的部分内容,或显示页码)。 -下面的示例在文档右下角绘制进度条,向下滚动时更新进度条: +以下示例在文档上方绘制一个进度条,并在您向下滚动时更新它来填充: ```html -
-

Scroll me...

+
``` -将元素的position属性指定为fixed时,其行为和absolute很像,但可以防止在文档滚动时期跟着文档一起滚动。其效果是使及进度条一直待在角落。进度条内还有其他元素,会随着当前进度改变尺寸。我们使用%,而非px作为宽度单位,这使得元素尺寸是相对于整个进度条来计算的。 +将元素的position属性指定为fixed时,其行为和absolute很像,但可以防止在文档滚动时期跟着文档一起滚动。其效果是让我们的进度条呆在最顶上。 改变其宽度来指示当前进度。 在设置宽度时,我们使用`%`而不是`px`作为单位,使元素的大小相对于页面宽度。 -innerHeight全局变量是窗口高度,我们必须要减去滚动条的高度。你点击文档底部的时候是无法继续滚动的(和innerHeight一样,还有innerWidth变量)。使用pageYOffset(当前滚动位置)除以最大滚动位置,并乘以100,就可以得到进度条长度。 +innerHeight全局绑定是窗口高度,我们必须要减去滚动条的高度。你点击文档底部的时候是无法继续滚动的。对于窗口高度来说,也存在`innerWidth`。使用pageYOffset(当前滚动位置)除以最大滚动位置,并乘以100,就可以得到进度条长度。 调用滚动事件的preventDefault无法阻止滚动。实际上,事件处理器是在进行滚动之后才触发的。 -### 14.10 焦点事件 +## 焦点事件 -当元素获得焦点时,浏览器会触发其上的focus事件。当失去焦点时触发blur事件。 +当元素获得焦点时,浏览器会触发其上的focus事件。当失去焦点时,元素会获得blur事件。 与前文讨论的事件不同,这两个事件不会传播。子元素获得或失去焦点时,不会激活父元素的处理器。 @@ -344,18 +363,18 @@ innerHeight全局变量是窗口高度,我们必须要减去滚动条的高度 ```html

Name:

-

Age:

+

Age:

-``` +我们在第 11 章中看到了`setTimeout`函数。 它会在给定的毫秒数之后,调度另一个函数在稍后调用。 有时读者需要取消调度的函数。可以存储setTimeout的返回值,并将作为参数调用clearTimeout。 ```html -var bombTimer = setTimeout(function() { +let bombTimer = setTimeout(() => { console.log("BOOM!"); }, 500); @@ -434,8 +444,8 @@ if (Math.random() < 0.5) { // 50% chance 还有setInterval和clearInterval这种相似的函数,用于设置计时器,每隔一定毫秒数重复执行一次。 ```html -var ticks = 0; -var clock = setInterval(function() { +let ticks = 0; +let clock = setInterval(() => { console.log("tick", ticks++); if (ticks == 10) { clearInterval(clock); @@ -444,24 +454,22 @@ var clock = setInterval(function() { }, 200); ``` -### 14.14 降频 +## 降频 -某些类型的事件可能会连续、迅速触发多次(例如mousemove和scroll事件)。处理这类事件时,你必须小心谨慎,防止处理任务耗时过长,否则处理器会占据过多事件,导致用户与文档交互变得非常慢且卡顿。 +某些类型的事件可能会连续、迅速触发多次(例如mousemove和scroll事件)。处理这类事件时,你必须小心谨慎,防止处理任务耗时过长,否则处理器会占据过多事件,导致用户与文档交互变得非常慢。 若你需要在这类处理器中编写一些重要任务,可以使用setTimeout来确保不会频繁进行这些任务。我们通常称之为“事件降频(Debounce)”。有许多方法可以完成该任务。 -在第一个示例中,当用户输入某些字符时,我们想要完成某些任务,但我们不想在每个按键事件中立即处理该任务。当用户输入过快时,我们希望暂停一下然后进行处理。我们不是立即在事件处理器中执行动作,而是设置一个定时器。我们也会清除上一次的定时器(如果有),因此当两个事件触发间隔过短(比定时器延时短),就会取消上一次事件设置的定时器。 +在第一个示例中,当用户输入某些字符时,我们想要有所反应,但我们不想在每个按键事件中立即处理该任务。当用户输入过快时,我们希望暂停一下然后进行处理。我们不是立即在事件处理器中执行动作,而是设置一个定时器。我们也会清除上一次的定时器(如果有),因此当两个事件触发间隔过短(比定时器延时短),就会取消上一次事件设置的定时器。 ```html ``` @@ -472,64 +480,58 @@ var clock = setInterval(function() { ```html ``` -### 14.15 本章小结 +## 本章小结 -事件处理器可以检测并响应事件,而不需要直接控制事件。addEventListener方法用于注册处理器。 +事件处理器可以检测并响应发生在我们的 Web 页面上的事件。addEventListener方法用于注册处理器。 每个事件都有标识事件的类型(keydown、focus等)。大多数方法都会在特定DOM元素上调用,接着向其父代节点传播,允许每个父代元素的处理器都能处理这些事件。 JavaScript调用事件处理器时,会传递一个包含事件额外信息的事件对象。该对象也有方法支持停止进一步传播(stopPropagation),也支持阻止浏览器执行事件的默认处理器(preventDefault)。 -按下键盘按键时会触发keydown、keypress和keyup事件。按下鼠标按钮时,会触发mousedown、mouseup和click事件。移动鼠标会触发mousemove事件,也可能触发mouseenter和mouseout事件。 +按下键盘按键时会触发keydown和keyup事件。按下鼠标按钮时,会触发mousedown、mouseup和click事件。移动鼠标会触发mousemove事件。触摸屏交互会导致`"touchstart"`,`"touchmove"`和`"touchend"`事件。 我们可以通过scroll事件监测滚动行为,可以通过focus和blur事件监控焦点改变。当文档完成加载后,会触发窗口的load事件。 -同时只能执行一段JavaScript程序。因此,事件处理器和其他调度脚本需要等待脚本结束,才能得到机会执行。 +## 习题 -### 14.16 习题 +### 气球 -#### 14.16.1 少了几个按键的键盘 +编写一个显示气球的页面(使用气球 emoji,`\ud83c\udf88`)。 当你按下上箭头时,它应该变大(膨胀)10%,而当你按下下箭头时,它应该缩小(放气)10%。 -在1928年和1933年之间,土耳其法律禁止在官方文档中使用Q、W和X。这是用于扼杀库尔德的文化大量措施中的一部分。这些字母在库尔德人中使用,但伊斯坦布尔的土耳其人不使用。 +您可以通过在其父元素上设置`font-size` CSS 属性(`style.fontSize`)来控制文本大小(emoji 是文本)。 请记住在该值中包含一个单位,例如像素(`10px`)。 -作为一个练习,通过技术来实现这种阉割键盘按键的功能,编写一个文本域(使用<input type="text"标签),使得用户无法输入这些字母。 +箭头键的键名是`"ArrowUp"`和`"ArrowDown"`。确保按键只更改气球,而不滚动页面。 -(不用处理复制粘贴,以及其他可能的漏洞。) +实现了之后,添加一个功能,如果你将气球吹过一定的尺寸,它就会爆炸。 在这种情况下,爆炸意味着将其替换为“爆炸 emoji,`\ud83d\udca5`”,并且移除事件处理器(以便您不能使爆炸变大变小)。 ```html - +

💥

``` -#### 14.16.2 鼠标轨迹 +### 鼠标轨迹 在JavaScript早期,有许多主页都会在页面上使用大量的动画,人们想出了许多该语言的创造性用法。 -其中一种用途是“鼠标踪迹”,也就是沿着鼠标指针在页面上滑动的轨迹画出一连串图像。 +其中一种是“鼠标踪迹”,也就是一系列的元素,随着你在页面上移动鼠标,它会跟着你的鼠标指针。 -在本习题中实现鼠标轨迹的功能。使用绝对定位、固定尺寸的<div>元素,背景为黑色(请参考鼠标点击一节中的示例)。创建一系列此类元素,当鼠标移动时,伴随鼠标指针显示它们。 +在本习题中实现鼠标轨迹的功能。使用绝对定位、固定尺寸的
元素,背景为黑色(请参考鼠标点击一节中的示例)。创建一系列此类元素,当鼠标移动时,伴随鼠标指针显示它们。 有许多方案可以实现我们所需的功能。你可以根据你的需要实现简单的或复杂的方法。简单的解决方案是保存固定鼠标的轨迹元素并循环使用它们,每次mousemove事件触发时将下一个元素移动到鼠标当前位置。 @@ -551,24 +553,24 @@ JavaScript调用事件处理器时,会传递一个包含事件额外信息的 ``` -#### 14.16.3 选项卡界面 +### 选项卡 -选项卡界面是常见的设计模型。选项卡支持用户通过选择一系列元素上突出的标签来选择一个面板。 +选项卡面板广泛用于用户界面。它支持用户通过选择元素上方的很多突出的选项卡来选择一个面板。 -本习题要求实现一个简单的选项卡界面。编写asTabs函数,接受一个DOM节点并创建选项卡界面来展现该节点的子元素。该函数应该在顶层节点中插入大量<button>元素,与每个孩子元素一一对应,按钮文本从孩子的data-tabname中获取。除了显示一个初始孩子节点,其他孩子节点都应该隐藏(将display样式设置成none),并通过点击按钮来选择当前显示的节点。 +本习题中,你必须实现一个简单的选项卡界面。编写asTabs函数,接受一个DOM节点并创建选项卡界面来展现该节点的子元素。该函数应该在顶层节点中插入大量