在浏览器上显示的页面中,会发生
- 按钮被点击(双击)
- 鼠标指针移动到字符串上(移出到字符串外)
- 输入框的内容改变了
等各种各样的事件(Event)。客户端JavaScript中的特征就是根据这些事件记述相应的代码。我们将这个编程模型称为事件驱动模型(Event driven programming)。
...页面加载时的处理...
...点击时的处理...
...文本改变时的处理...
事件驱动模型:根据页面中发生的各种事件(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中可以使用的主要事件 |
Note mouseover/mouseout和mouseenter/mouseleave的不同
mouseover/mouseout和mouseenter/mouseleave虽然都是鼠标位于元素上方时,鼠标从元素上离开时发生的事件,但是它们的动作还是稍微有些差异。具体是当元素有子元素时,如果监听外侧的元素(id="parent"),会有以下差异。
●mouseover/mouseout和mouseenter/mouseleave的不同
mouseenter/mouseleave事件只是在进出目标元素时触发的,而mouseover/mouseout事件在进出内部的元素时也会触发。为了避免意外的动作,请好好理解两者的差异。
■定义事件处理器/事件监听器
正如之前所说的,事件驱动模型的中心是「事件」和「事件处理器/事件监听器」。在事件监听模型中,首先要定义以下3个内容。
- 在哪个元素中发生的
- 哪个事件
- 关联哪个事件处理器/事件监听器
在客户端JavaScript中,有以下用来进行关联的方法。
- 作为标签内的属性声明
- 作为元素对象的属性声明
- 使用addEventListener方法声明
首先,应该使用在DOM Level 2中定义的标准化了的addEventListener方法。但是,因为1~2的方法简单而经常使用,所以这里也一起介绍。
顺便说一下,将1~2中声明的事件处理称为「事件处理器」,将3中声明的称为「事件监听器」这样做区分(两者决定性的差异是声明的方式)。
#####(1)作为标签内的属性声明
这个是最简单的写法。下面是点击提交按钮后显示警告对话框的例子。
●清单6-10 handle.html(上)/handler.js(下)
"显示对话框"
'按钮被点击了。'
JavaScript完全学习教程
显示对话框
localhost的内容:
按钮被点击了。
禁止此页面再显示对话框
●点击按钮时显示对话框
关键是清单中的粗体字部分。在标签内声明事件处理器时,请如下记述。
●语法 设定事件处理器(1)
<标签名 on事件名="JavaScript的代码">
通常在「JavaScript的代码」中,是像清单6-10这样用来调用事件处理器(函数)的代码——也就是说,记述「btn_click()」这样的代码。但是,如果当处理非常简单时,也可以在这里直接记述处理本身。也就是说,清单6-10也可以像下面这样改写。
●清单6-11 handler2.html
<input type="button" value="显示对话框"
onclick="window.alert('按钮被点击了。');" />
但是,在标签内书写过于复杂的JavaScript代码,从代码的可读性的角度来看也好,鉴于最近流行的「应该明确地分离页面的构成和处理(脚本)」也好,这都不是令人满意的写法。清单6-11中的写法只是用来书写很简单的处理的。请记住,通常「标签内的JavaScript代码,仅仅是用来调用事件处理器的」。
虽说只是调用事件处理器,但是在原本是应该用来定义外观布局的HTML中混入JavaScript的代码也是不太好的。因此,也可以在JavaScript的代码中添加关联和定义事件监听器本身。下面,是改写清单6-10的代码的例子。
●清单6-12 handler3.html(上)/handler3.js(下)
"显示对话框"
// 页面加载时注册要执行的事件处理器
// 注册点击按钮(btn)时执行的事件处理器
'按钮被点击了。'
obj:windwo对象、或者是元素对象
event:事件名
statements:事件发生时应该执行的处理
在这个例子中,定义了window(页面)加载时应该执行的处理和``元素被点击时的处理。
不是匿名函数(函数字面量),而是像下面这样书写函数名,事件处理器(函数)本身可以另外定义。
**●语法 注册事件处理器(2)**  > obj:window对象,或者是元素对象
event:事件名
func:函数名
但是,因为事件处理器的特性,基本不会在多个地方使用。考虑到这一点,相比另外定义命名函数,直接定义匿名函数,可以节省全局命名空间,代码本身也更加简单。
使用这个写法时,请注意以下几点。
- 事件名都写作小写
事件名都必须使用小写(如果是作为标签内的属性,则不区分大写/小写)。也就是说不能像「window.onLoad」、「~.onClick」这样书写。
- 作为属性设定的是函数对象
设定为属性时,只能是函数对象,而不是函数调用。例如,给onload事件关联init事件处理器时,
window.onload = init();
这样的写法是不正确的。正确的写法如下。
window.onload = init;
- 个别元素的事件处理器应该放在onload事件处理器中
以「document.getElementById.~」的形式注册事件处理器时,通常需要写在onload事件处理器中。通过使用onload事件处理器,会在页面读取完成之后执行处理。
如果在页面整体被读入之前调用getElementById方法,可能会获取不到目标元素而造成事件处理器设定失败。
在本书中,因为是在</body>
闭标签之前书写<script>
元素的,所以即使没有onload事件处理器代码也可以正常运行。但是,如果要不论<script>
元素的位置在哪里代码都可以正常运行,就需要使用onload事件处理器。
虽然使用onxxxx属性设定事件处理器是在客户端JavaScript的世界中一直以来的用法,但是也存在一个问题。这就是
不能给同一个元素/同一个事件设定多个事件处理器
在开发简单的应用时可能不会觉得有什么问题。但是,如果是组合使用多个库时会怎么样呢?如果1个库使用了某个元素的某个事件,其他的库中使用了同一个元素的同一个事件的处理就无法运行了(当然,自己写的代码也是同样的)。
这里登场的就是事件监听器了。把事件监听器理解为「可以对同一个元素的同一个事件添加多个关系的事件处理器」就可以了。
addEventListener方法的功能是设定事件监听器。
●语法 addEventListener方法
elem:元素对象
type:事件的种类
listener:根据事件应该要执行的处理
capture:事件的方向(6.7.3)
下面,是使用addEventListener方法改写清单6-12的代码的例子。
**●清单6-13 handler4.html(上)/handler4.js(下)**  > "显示对话框"
// 注册页面加载时执行的事件处理器
注册点击按钮(btn)时执行的事件处理器
'按钮被点击了。'
DOMContentLoaded事件监听器和之前的onload事件处理器相同,都是「页面加载后执行处理」的意思。
但是,和onload事件处理器的执行时间有细微的差异。
- onload事件处理器 → 内容主体和所有的图片都加载完成后执行
- DOMContentLoaded事件监听器 → 内容主体加载完成后执行(=不等待图片的加载)
大部分的处理应该是不需要等待图片的加载的,所以使用DOMContentLoaded事件监听器时,脚本的开始事件会提前些。请记住,如果没有关于图片的处理这样的特别的理由,
通常是使用DOMContentLoaded事件监听器来表示页面的初始化处理