Skip to content

Latest commit

 

History

History
141 lines (126 loc) · 10.2 KB

6.2.3.md

File metadata and controls

141 lines (126 loc) · 10.2 KB

6.2.3 触发事件并执行处理 -事件驱动模型-

在浏览器上显示的页面中,会发生

  • 按钮被点击(双击)
  • 鼠标指针移动到字符串上(移出到字符串外)
  • 输入框的内容改变了

等各种各样的事件(Event)。客户端JavaScript中的特征就是根据这些事件记述相应的代码。我们将这个编程模型称为事件驱动模型(Event driven programming)。

【292页】

image

...页面加载时的处理...
...点击时的处理...
...文本改变时的处理...
事件驱动模型:根据页面中发生的各种事件(Event)调用、执行相应的处理的模型

●事件驱动(Event driven)模型

  这时,将定义事件相应的处理内容的代码块(函数)称为事件处理器或者是事件监听器。  下面是客户端JavaScript中可以使用的主要事件。当然,也没有必要理解这些所有的事件,「有这样的事情啊」的程度可以了。

分类 事件名 发生时间 主要的目标元素
读取 abort 中断读取图片时 img
load 完成读取页面/图片时 body、img
unload 移动到其他页面时 body
鼠标 click 点击时 -
dblclick 双击时 -
mousedown 按下鼠标时 -
mouseup 松开鼠标时 -
mousemove 移动鼠标指针时 -
mouseover 当鼠标指针位于元素上方时 -
mouseout 当鼠标从元素上移开时 -
mouseenter 当鼠标指针位于元素上方时 -
mouseleave 当鼠标从元素上移开时 -
contextmenu 右键显示菜单前 body
键盘 keydown 按下按键时 -
keypress 按住按键时 -
keyup 松开按键时 -
表单 change 内容变更时 input(text)、select
reset 按下重置按钮后 form
submit 按下提交按钮后 form
焦点 blur 元素失去焦点时 -
focus 元素获取焦点时 -
其他 resize 元素大小改变时 -
scroll 滚动时 body
(下一页继续)
●客户端JavaScript中可以使用的主要事件
【293页】

Note mouseover/mouseout和mouseenter/mouseleave的不同
  mouseover/mouseout和mouseenter/mouseleave虽然都是鼠标位于元素上方时,鼠标从元素上离开时发生的事件,但是它们的动作还是稍微有些差异。具体是当元素有子元素时,如果监听外侧的元素(id="parent"),会有以下差异。 image ●mouseover/mouseout和mouseenter/mouseleave的不同

  mouseenter/mouseleave事件只是在进出目标元素时触发的,而mouseover/mouseout事件在进出内部的元素时也会触发。为了避免意外的动作,请好好理解两者的差异。

■定义事件处理器/事件监听器
  正如之前所说的,事件驱动模型的中心是「事件」和「事件处理器/事件监听器」。在事件监听模型中,首先要定义以下3个内容。

  • 在哪个元素中发生的
  • 哪个事件
  • 关联哪个事件处理器/事件监听器

  在客户端JavaScript中,有以下用来进行关联的方法。

  1. 作为标签内的属性声明
  2. 作为元素对象的属性声明
  3. 使用addEventListener方法声明
【294页】

  首先,应该使用在DOM Level 2中定义的标准化了的addEventListener方法。但是,因为1~2的方法简单而经常使用,所以这里也一起介绍。
  顺便说一下,将1~2中声明的事件处理称为「事件处理器」,将3中声明的称为「事件监听器」这样做区分(两者决定性的差异是声明的方式)。 #####(1)作为标签内的属性声明   这个是最简单的写法。下面是点击提交按钮后显示警告对话框的例子。

●清单6-10 handle.html(上)/handler.js(下) image

"显示对话框"
'按钮被点击了。'
JavaScript完全学习教程
显示对话框
localhost的内容:
按钮被点击了。
禁止此页面再显示对话框

●点击按钮时显示对话框

  关键是清单中的粗体字部分。在标签内声明事件处理器时,请如下记述。

●语法 设定事件处理器(1)

<标签名 on事件名="JavaScript的代码">

  通常在「JavaScript的代码」中,是像清单6-10这样用来调用事件处理器(函数)的代码——也就是说,记述「btn_click()」这样的代码。但是,如果当处理非常简单时,也可以在这里直接记述处理本身。也就是说,清单6-10也可以像下面这样改写。

●清单6-11 handler2.html

<input type="button" value="显示对话框"
    onclick="window.alert('按钮被点击了。');" />
【295页】

  但是,在标签内书写过于复杂的JavaScript代码,从代码的可读性的角度来看也好,鉴于最近流行的「应该明确地分离页面的构成和处理(脚本)」也好,这都不是令人满意的写法。清单6-11中的写法只是用来书写很简单的处理的。请记住,通常「标签内的JavaScript代码,仅仅是用来调用事件处理器的」。

(2)作为元素对象的属性声明

  虽说只是调用事件处理器,但是在原本是应该用来定义外观布局的HTML中混入JavaScript的代码也是不太好的。因此,也可以在JavaScript的代码中添加关联和定义事件监听器本身。下面,是改写清单6-10的代码的例子。

●清单6-12 handler3.html(上)/handler3.js(下) image

"显示对话框"
// 页面加载时注册要执行的事件处理器
// 注册点击按钮(btn)时执行的事件处理器
'按钮被点击了。'

写法如下。

●语法 注册事件处理器(1) image

obj:windwo对象、或者是元素对象
event:事件名
statements:事件发生时应该执行的处理


  在这个例子中,定义了window(页面)加载时应该执行的处理和``元素被点击时的处理。
  不是匿名函数(函数字面量),而是像下面这样书写函数名,事件处理器(函数)本身可以另外定义。

**●语法 注册事件处理器(2)** ![image](/images/c6/295-3.png) > obj:window对象,或者是元素对象
event:事件名
func:函数名
【296页】

  但是,因为事件处理器的特性,基本不会在多个地方使用。考虑到这一点,相比另外定义命名函数,直接定义匿名函数,可以节省全局命名空间,代码本身也更加简单。
  使用这个写法时,请注意以下几点。

  • 事件名都写作小写

  事件名都必须使用小写(如果是作为标签内的属性,则不区分大写/小写)。也就是说不能像「window.onLoad」、「~.onClick」这样书写。

  • 作为属性设定的是函数对象

  设定为属性时,只能是函数对象,而不是函数调用。例如,给onload事件关联init事件处理器时,

window.onload = init();

这样的写法是不正确的。正确的写法如下。

window.onload = init;
  • 个别元素的事件处理器应该放在onload事件处理器中

  以「document.getElementById.~」的形式注册事件处理器时,通常需要写在onload事件处理器中。通过使用onload事件处理器,会在页面读取完成之后执行处理。
  如果在页面整体被读入之前调用getElementById方法,可能会获取不到目标元素而造成事件处理器设定失败。
  在本书中,因为是在</body>闭标签之前书写<script>元素的,所以即使没有onload事件处理器代码也可以正常运行。但是,如果要不论<script>元素的位置在哪里代码都可以正常运行,就需要使用onload事件处理器。

(3)声明addEventListener方法

  虽然使用onxxxx属性设定事件处理器是在客户端JavaScript的世界中一直以来的用法,但是也存在一个问题。这就是

不能给同一个元素/同一个事件设定多个事件处理器

  在开发简单的应用时可能不会觉得有什么问题。但是,如果是组合使用多个库时会怎么样呢?如果1个库使用了某个元素的某个事件,其他的库中使用了同一个元素的同一个事件的处理就无法运行了(当然,自己写的代码也是同样的)。

【297页】

  这里登场的就是事件监听器了。把事件监听器理解为「可以对同一个元素的同一个事件添加多个关系的事件处理器」就可以了。
  addEventListener方法的功能是设定事件监听器。

●语法 addEventListener方法 image

elem:元素对象
type:事件的种类
listener:根据事件应该要执行的处理
capture:事件的方向(6.7.3)


  下面,是使用addEventListener方法改写清单6-12的代码的例子。

**●清单6-13 handler4.html(上)/handler4.js(下)** ![image](/images/c6/297-2.png) > "显示对话框"
// 注册页面加载时执行的事件处理器
注册点击按钮(btn)时执行的事件处理器
'按钮被点击了。'

  DOMContentLoaded事件监听器和之前的onload事件处理器相同,都是「页面加载后执行处理」的意思。
  但是,和onload事件处理器的执行时间有细微的差异。

  • onload事件处理器 → 内容主体和所有的图片都加载完成后执行
  • DOMContentLoaded事件监听器 → 内容主体加载完成后执行(=不等待图片的加载)

  大部分的处理应该是不需要等待图片的加载的,所以使用DOMContentLoaded事件监听器时,脚本的开始事件会提前些。请记住,如果没有关于图片的处理这样的特别的理由,

通常是使用DOMContentLoaded事件监听器来表示页面的初始化处理