事件类型

事件大致可以分成几类,了解这些分类将有助于理解和组织如下长长的事件列表:

依赖于设备的输入事件:有些事件和特定的输入设备直接相关,比如鼠标和键盘。包括诸如“mousedown”、“mousemove”、“touchmove”和“gesturechange”等。

独立于设备的输入事件:有些输入事件没有直接相关的输入设备。

用户界面事件:用户界面事件是较高级的事件,通常出现在定义Web应用用户界面的HTML变淡元素上。包括文本输入域获取键盘焦点的focus事件、用户改变表单元素显示值的change事件和用户单机表单的“提交”按钮的submit事件。

状态变化事件:有些事件不是由用户活动,而是网络或浏览器活动触发,用来表示某种生命周期或相关状态的变化。

特定API事件:HTML5及相关规范定义的大量Web API都有自己的事件类型。

计时器和错误处理程序:timer和error handler

传统事件类型

1、表单事件

submit和reset事件、change、focus、blur等事件。

注意:无论用户何时输入文字到<textarea>和其他文本输入表单元素,除IE外的浏览器都会触发input事件。不像change事件,每次文字插入都会触发input事件。

2、Window事件

Window事件是指事件的发生与浏览器窗口本身而非窗口中显示的任何特定文档内容相关。但是,这些事件中有一些会和文档元素上发生的事件同名。

load事件是这些事件中最重要的一个,当文档和其所有外部资源完全加载并显示给用户时就会触发它。

unload事件和load相对,当用户离开当前文档转向其他文档时会触发它。unload事件处理程序可以用于保存用户的状态,但它不能用于取消用户转向其他地方。beforeunload事件和unload类似,但它能提供询问用户是否确定离开当前页面的机会。

onerror属性有点像事件处理程序,当JavaScript出错时会出发它。但是,它不是真正的事件处理程序,因为它能用不同的参数来调用。

当用户调整浏览器窗口大小或滚动它时会触发resize和scroll事件。scroll事件也能在任何可以滚动的文档元素上触发。传递给resize和scroll事件处理程序的事件对象是一个非常普通的Event对象,它没有指定调整大小或发生滚动的详细信息属性。

3、鼠标事件

当用户在文档上移动或单击鼠标时都会产生鼠标事件。这些事件在鼠标指针所对应的最深嵌套元素上触发,但他们会冒泡直到文档最顶层。传递给鼠标事件处理程序的事件对象有属性集,他们描述了当事件发生时鼠标的位置和按键状态,也指明当时是否有任何辅助键按下。

4、键盘事件

当键盘聚焦到Web浏览器时,用户每次按下或释放键盘上的按键时都会产生事件。键盘快捷键对于操作系统和浏览器本身有特殊意义,它们经常被操作系统或浏览器“吃掉”并对JavaScript事件处理程序不可见。

注册事件处理程序

注册事件处理程序有两种基本方式。第一种出现在Web初期,给事件目标对象或文档元素设置属性。第二种方式更新并且更通用,将事件处理程序传递给对象或元素的一个方法。

设置JavaScript对象属性为事件处理程序

注册事件处理程序最简单的方式就是通过设置事件目标的属性为所需事件处理程序函数。按照约定,事件处理程序属性的名字由“on”后面跟着事件名组成:onclick、onchange、onload、onmouseover等。注意这些属性名是区分大小写,所有都是小写,即使事件类型是由多个词组成。

事件处理程序属性的缺点是其设计都是围绕着假设每个事件目标对于每种事件类型将最多只有一个处理程序。如果想编写能够在任意文档中都能使用的脚本库代码,更好的方式是使用一种不修改或覆盖任何已经注册处理程序的技术。

 设置HTML标签属性为事件处理程序

用于设置的文档元素事件处理程序属性也能换成对应HTML标签的属性,如果这样做,属性值应该是JavaScript代码字符串。这段代码应该是事件处理程序函数的主题,而非完整的函数声明。

如果HTML事件处理程序属性包含多条JavaScript语句,要记住必须使用分号分隔这些语句或断开属性值使其跨多行。

 addEventListener()

addEventListener()接受三个参数。第一个是要注册处理程序的事件类型,这个事件类型(或名字)是字符串,但它不应该包括用于设置事件处理程序属性的前缀“on”。第二个参数是当指定类型的事件发生时应该调用的函数。最后一个参数是布尔值。通常情况下,会给这个参数传递false。如果相反传递了true,那么函数将注册为捕获事件处理程序,并在事件不同的阶段调用。

相对addEventListener()的是removeEventListener()方法,它同样有三个参数,从对象中删除事件处理程序函数而非添加,它常用语临时注册事件处理程序,然后不久就删除它。

 attachEvent()

attachEvent()和detachEvent()方法的工作原理与addEventListener()和removeEventListerner()类似,但有如下例外:

  • 因为IE事件不支持事件捕获,所以attachEvent()和detachEvent()要求只有两个参数:事件类型和处理程序函数。
  • IE方法的第一个参数使用了带“on”前缀的事件处理程序属性名,而非没有前缀的事件类型。
  • attachEvent()允许相同的事件处理程序函数注册多次,当特点的事件类型发生时,注册函数的调用次数和注册一样。

var b = document.getElementById(“mybutton”);

var handler = function(){alert(“Thanks”);};

if(b.addEventListener)

b.addEventListener(“click”, handle, false)

else if(b.attachEvent)

b.attachEvent(“onclick”, handler)

 事件处理程序的调用

一旦注册了事件处理程序,浏览器就会在指定对象上发生指定类型事件时自动调用它。

 事件处理程序的参数

通常调用事件处理程序时把事件对象作为他们的一个参数。当通过设置HTML属性注册事件处理程序时,浏览器会把JavaScript编码转换到一个函数中。非IE浏览器使用event参数来构造函数,而IE在构造函数时没有要求参数。如果在这样的函数中使用event标识符,那么引用的正是window.event。

 事件处理程序的作用域

事件处理程序在其定义时的作用域而非调用时的作用域中执行,并且他们能存取那个作用域中的任何一个本地变量。但是,通过HTML属性来注册事件处理程序是一个例外,它们被转换为能存取全局变量的顶级函数而非本地变量。但因为历史原因,它们运行在一个修改后的作用域链中。

HTML属性最不自然的地方那个包括冗长的代码串和修改后的作用域链允许有用的快捷方式,可以使用tagName代替this.tagName,使用getElementById()替代document.getElementById()。

另一方面,HTML事件处理程序中修改的作用域是陷阱之源,因为作用域链中每个对象的属性在全局对象中都有相同名字的属性。

 事件处理程序的返回值

通过设置对象属性或HTML属性注册事件处理程序的返回值有时是非常有意义的。通常情况下,返回false就是告诉浏览器不要执行这个事件相关的默认操作。

 调用顺序

文档元素或其他对象可以为指定事件类型注册多个事件处理程序。当适当的事件发生时,浏览器必须按照如下规则调用所有的事件处理程序。

  • 通过设置对象属性或HTML属性注册的处理程序一直优先调用
  • 使用addEventListener()注册的处理程序按照它们的注册顺序调用
  • 使用attachEvent()注册的处理程序可能按照任何顺序调用,所以代码不硬个依赖于调用顺序

事件传播

当事件目标是Window对象或其他一些单独对象时,浏览器简单的通过调用对象上适当的处理程序响应事件。当事件目标是文档或文档元素时,情况比较复杂,在调用自目标元素上的注册的事件处理函数后,大部分事件会“冒泡”到DOM树根。调用目标的父元素的事件处理程序,然后调用在目标的祖父元素上注册的事件处理程序。这会一直到Document对象,最后到达Window对象。

事件冒泡为大量单独文档元素上注册处理程序提供了替代方案,即在共同的祖先上注册一个处理程序来处理所有的事件。

发生在文档元素上的大部分事件都会冒泡,值得注意的例外是focus、blur和scroll事件。文档元素上的load事件会冒泡,但它会在Document对象上停止冒泡而不会传播到Window对象。只有当整个文档都加载完毕时才会触发Window对象的load事件。

 事件取消

在支持addEventListerner()的浏览器中,也能通过调用事件对象的preventDefault()方法取消事件的默认操作。在IE9之前的IE中,可以通过设置事件对象的returnValue属性为false来达到同样的效果。

function cancelHandler(event){

var event = event || window.event;

if(event.preventDefault) event.preventDefault();

if(event.returnValue) event.returnValue = false;

return false;

}

 文档加载事件

当文档加载解析完毕且所有延迟脚本都执行完毕时会触发DOMContentLoader事件,此时图片和异步脚本可能依旧在加载,但是文档已经为操作准备就绪了。

 鼠标事件

除“mouseenter”和“mouseleave”外所有事件都能冒泡

类型 说明

click

高级事件,当用户按下并释放鼠标按键或其他方式“激活”元素时触发

contextmenu

可以取消的事件,当上下文菜单即将出现时触发。当前浏览器在鼠标右击时显示上下文菜单,所以这个事件也能像click事件那样使用

dblclick

当用户双击鼠标时触发

mousedown

当用户按下鼠标按键时触发

mousemove

当用户移动鼠标时触发

mouseover

当鼠标进入元素时触发。relateTarget(在IE中是fromElement)指的是鼠标来自的元素

mouseout

当鼠标离开元素时触发。relateTarget(在IE中是toElement)指的是鼠标要去往的元素

mouseenter

类似“mouseover”,但不冒泡,IE将其引入,HTML5将其标准化,但尚未广泛实现

mouseleave

类似“mouseout”,但不冒泡。IE将其引入,HTML5将其标准化,但尚未广泛实现。

 拖放事件

拖放是在“拖放源”和“拖放目标”之间传输数据的用户界面,它可以存在相同应用之间也可以是不同应用之间。拖放是复杂的人机交互,用于实现拖放的API总是很复杂:

  • 它们必须和底层OS结合,使它们能够在不相关的应用间工作。
  • 它们必须适用于“移动”、“复制”和“链接”数据传输操作,允许拖放源和拖放目标通过设置限制允许的操作,然后让用户选择许可设置。
  • 它们必须为拖放源提供一种方式指定待拖动的图标或图像。
  • 它们必须为拖放源和拖放目标的DnD交互过程提供基于事件的通知。

 文本事件

keypress事件是较高级的事件,它表示产生了一个可打印字符。3级DOM事件规范草案定义一个更通用的textinput事件,不管来源,无论何时用户输入文本时都会触发它。

建议中的textinput事件和已经实现的textInput事件都传递一个简单的事件对象,它有一个用于保存输入文本的data属性。

通过keypress事件传递的对象更加混乱。一个keypress事件表示输入的单个字符。事件对象以数字Unicode编码的形式指定字符,所以必须用String.fromCharCode()把它转换成字符串。

keypress和textinput事件是在新输入的文本真正插入到聚焦的文档元素前触发,这就是这些事件处理程序能够取消事件和组织文本插入的原因。

 键盘事件

当用户在键盘上按下或释放按键时,会发生keydown和keyup事件。它们由辅助键、功能键和字母数字键产生,如果用户按键事件足够长会导致它开始重复,那么keyup事件到达之前会收到多个keydown事件。

这些事件相关的事件都有数字属性keyCode,指定了按下的键是哪个。对于产生可打印字符的按键,keyCode值是按键上出现的主要字符的Unicode编码。无论Shift键处于什么状态,字母键总是产生大写keyCode键,这是因为它们出现在物理键盘上。