本章内容:理解事件流、使用事件处理程序、不同的事件类型
JavaScript与HTML之间的交互是通过事件实现的。事件,就是文档或者浏览器窗口发生的一些特定的交互瞬间。可以使用侦听器(或处理程序)来预定事件,以便事件发生时执行相应的代码。这种在传统软件工程中被称为观察员模式,支持页面的行为与页面的外观之间的松散耦合。
一、事件流
当浏览器发展到第四代的时候(IE4及 Netscape Communicator 4),浏览器开发团队遇到了一个很有意思的问题:页面的哪一部分会拥有某个特定的事件?要明白这个问题问的是什么,可以想象画在一张纸上的一组同心圆。如果你把手指放在圆心上,那么你的手指指向的不是一个圆,而是纸上的所有圆。
同样:当你单机某个按钮,他们都认为单机事件不仅仅发生在按钮上,在单机按钮的同时,你也单机了按钮的容器元素,甚至单机了整个页面。
事件流描述的是从页面接收事件的顺序。但有意思的是,IE 和 Netscape 开发团队提出了差不多是完全相反的事件流概念。IE的事件流是事件冒泡流,而Netscape Communicator 的事件流是事件捕获流。
1.1、事件冒泡
IE的事件流叫做事件冒泡(event bubbling),即事件开始时由最具体的元素接收,然后逐级向上传播到较为不具体的节点(文档)。
Event Bubbling
click me
如果单机了页面的
(1):
(2):
(3):
(4):
下图展示了事件冒泡的过程
所有现代浏览器都支持事件冒泡,在具体实现上还是有一些差别。IE5.5及更早版本中的事件冒泡会跳过元素(直接到 Document)。IE9、Firefox、Chrome、Safari则将事件一直冒泡到window对象
1.2、事件捕获
Netscape Communicator团队提出的另一种事件流叫做事件捕获(event capturing)。事件捕获的思想是不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件。单机
(1):
(2):
(3):
(4):
下图展示事件捕获的过程
IE9、Safari、Chrome、Opera、Firefox目前都支持这种事件流模型
由于有点老版本的浏览器不支持,因此较少使用事件捕获。建议放心使用事件冒泡,在有特殊需要时再使用事件捕获
1.3、DOM事件流
"DOM2级事件" 规定的事件流包括三个阶段:事件捕获阶段、目标阶段、事件冒泡阶段。首先发生的是事件捕获阶段,为截取事件提供了机会;然后是实际的目标接收到事件;最后是冒泡阶段,可以在这个阶段对事件做出响应。 "目标阶段",事件在 事件就是用户或浏览器自身执行的某种动作。而响应某个事件的函数就叫做事件处理程序(或事件侦听器) 某个元素支持的每种事件,都可以使用一个与相应事件处理程序相同的HTML特性指定。 在 HTML 中定义的事件,也可以调用在页面其他地方定义的脚本 这样指定事件处理程序具有一些独到之处。首先,这样会创建一个封装着元素属性值的函数。这个函数中有一个全局变量 event,也就是事件对象。 通过 event 变量,可以直接访问事件对象,你不同自己定义它,也不用从函数的参数列表中读取。在这个函数内部,this 值等于事件的目标元素,例如: 关于这个动态创建的函数,另一个有意思的地方是它扩展作用域的方式。在这个函数内部,可以向访问局部变量一样访问 document及改元素本身的成员。这个函数使用 with 像下面这样扩展作用域: 如下一来,事件处理程序要访问自己的属性就简单多了 实际上,这样的扩展作用域的方式,无法就是想让事件处理程序无需引用表单元素就能访问其它表单字段,例如: 不过,在HTML 中指定事件处理程序有几个缺点: 通过JavaScript指定事件处理程序的传统方式,就是将一个函数赋值给一个事件处理程序属性。一直沿用至今,具有 简单、跨浏览器的优势。 每个元素都有自己的事件处理程序属性,这些属性通常全部小写,例如onclick。将这种属性的值设置为一个函数,就可以指定事件处理程序 使用DOM0 级方法指定的事件处理程序被认为是元素的方法,因此,这时候的事件处理程序是在 元素的作用域中运行的;换句话说,程序中的this引用当前元素 "DOM2级事件" 定义了两个方法,用于处理指定和删除事件处理程序的操作:addEventListener()、removeEventListener()。它们接受三个参数: 使用 DOM2 级方法添加事件处理程序的主要好处是可以为一个事件添加多个事件处理程序。 通过 addEventListener() 注册的事件处理程序 只能使用 removeEventListener() 来移除;移除时传入的参数与添加处理程序时传入的参数相同。这意味着通过 addEventListener() 添加的匿名函数将无法移除 虽然函数看上去是一致的,但实际上两个函数不是同一个。 IE 在 IE 中使用 attachEvent() 与使用 DOM0 级方法的主要区别在于事件处理程序的作用域。 类是的,attachEvent() 也可以为同一个事件 添加多个事件处理程序。 不过与DOM方法不同的是,这些事件处理程序不是以添加它们的顺序执行,而是以相反的顺序被触发。 使用 attachEvent() 添加的事件可以通过 detachEvent() 来移除,条件是必须提供相同的参数(与DOM一样,不能使用匿名函数) 可以像下面这样使用 EventUtil 对象: addHandler() 和 removeHandler() 并没有考虑到所有的浏览器问题,例如在IE中的作用域问题。 触发DOM上的某个事件时,会产生一个事件对象 event,这个对象中包含着所有与事件相关的信息。 兼容DOM的浏览器会将一个 event 对象传入到事件处理程序中。 在通过 HTML 特性指定事件处理程序时,变量 event 中保存着 event 对象。 event 对象包含于创建它的特定事件有关的属性和方法,所有的事件都会有下表列出的成员。 在事件处理程序内部,对象 this 始终等于 currentTarget 的值,而 target 则只包含事件的实际目标。如果直接将事件处理程序指定给了目标元素,则 this、currentTarget、target包含相同的值。 在需要通过一个函数处理多个事件时,可以利用 type 属性实现 要阻止特定事件的默认行为,可以使用 preventDefault() 方法。 stopPropagation() 方法用于立即停止事件在 DOM 层次中的传播,即取消进一步的事件捕获或冒泡。 事件对象的 eventPhase属性,可以用来确定事件当前正位于事件流的哪个阶段。 与访问DOM中的event 对象不同,要访问IE中的 event 对象有几种不同的方式,取决于指定事件处理程序的方法。 在使用DOM0级方法添加事件处理程序时,event 对象作为window 对象的一个属性存在。 如果事件处理程序是使用 attachEvent() 添加的,那么就会有一个 event 对象作为参数被传入事件处理程序函数中。 如果是通过 HTML 特性指定的事件处理程序,那么还可以通过一个名叫 event的变量来访问 event 对象 IE 的 event 对象同样也包含以创建它的事件相关的属性和方法。下列是所有事件对象都会包含的属性和方法 因为事件处理程序的作用域是根据指定它的方式来确定的,所以不能认为 this 会始终等于事件目标。故而,最好还是使用 event.srcElement 比较保险。 returnValue 属性相当于 DOM 中的 preventDefault() 方法,他们的作用域都是取消给定事件的默认行为。只要将 returnValue 设置为 false,就可以阻止默认行为。 cancelBubble 属性 与 DOM 中的 stopPropagation() 方法作用相同,都是用来停止事件冒泡的。由于IE不支持事件捕获,因而只能取消事件冒泡;但stopPropagation() 可以同时取消 事件冒泡和捕获 根据上面介绍的属性,对前面的 EventUtil 对象加以增强 “DOM3级事件” 规定了以下几类事件 除了这几类事件之外,HTML5也定义了一组事件,有些浏览器还会在DOM和BOM中实现其他专有事件,这些专有的事件一般都是根据开发人员需求定制的,没有什么规范,因此不同浏览器的实现有可能不一致。 DOM3 级事件模块在 DOM2级事件模块基础上重新定义了这些事件,也添加了一些新事件。包括IE9在内的所有主流浏览器都支持DOM2 级事件。IE9也支持DOM3级事件 UI事件指的是那么不一定于用户操作有关的事件 检测 浏览器是否支持 DOM2级 或 DOM3级事件 当页面加载完成后(包括所有图像、JavaScript文本、CSS文件等外部资源),就会触发window 上面的 load 事件。 第一种定义方式是使用如下所示的JavaScript代码 第二种指定 方式是通过为 实际上,后面这种方法只是为了保证向后兼容的一种权宜之计,但所有浏览器都能很好地支持这种方式,当然建议使用 JavaScript 的方式。 图像上面也可以触发 load 事件,无论是在 DOM种的图像元素还是在HTML中的图像元素。 在创建新的元素时,可以为其指定一个事件处理程序,以便图像加载完毕后给出提示。重要的是要在指定src属性之前先指定事件 也可以通过使用 DOM0 级的 Image 对象实现。可以像使用 元素一样使用 Image 对象,只不过无法将其添加到DOM树中 还有一些元素也以非标准的方式支持 load 事件。在IE9、Firefox、Opera、Chrome、Safari3+及更高的版本中, 元素和 元素也会触发load事件,将它们添加到文档并且设置了 src/href 属性后,就会开始下载文件。 与 load 事件对于的是 unload 事件,这个事件在文档被完全卸载后触发。只要用户从一个页面切换到另一个页面,就会发生 unload 事件。而利用这个事件最多的情况就是清除引用,以避免内存泄漏。 需要注意的是:onload 事件是在一切都被卸载之后才触发,那么在页面加载后存在的那些对象,此时就不一定存在了。此时,操作DOM节点或者元素的样式就会导致错误 当浏览器窗口被调到一个新的高度或宽度时,就会触发 resize 事件。这个事件在 window 上面触发,因此可以通过 JavaScript 或者 scroll 事件是在 window 对象上发生的,但它实际表示的则是页面中相应元素的变化。 焦点事件会在页面元素获得或失去焦点时触发。利用这些事件并于 document.hasFocus() 方法及 document.activeElement 属性配合使用,可以知晓用户在页面上的行踪 当焦点聪慧页面的一个元素移动到另一个元素,会依次触发下列事件 检测浏览器是否支持这些事件 鼠标事件是 Web 开发中最常用的一类事件,毕竟鼠标还是最主要的定位设备。DOM3 级事件中定义了 9个鼠标事件。如下: 在同一个元素上,上诉事件的触发过程 检测浏览器是否支持上面所有的事件 鼠标事件中还有一类滚轮事件,即滚轮事件,其实就是一个 mousewheel 事件。这个事件跟踪鼠标滚轮,类似于Mac的触控板。 鼠标事件都是在浏览器视口中的特定位置上发生的。这个位置信息保存在事件对象的clientX 和 clientY 属性中。它们的值表示事件发生时鼠标指针在视口中水平和垂直坐标 可以使用类似下列代码获取鼠标事件的客户端坐标信息 通过事件对象的 pageX 和 pageY 属性,表示鼠标光标在页面中的位置,因此坐标是从页面本身而非视口计算。 在IE8及更早版本不支持事件对象上面的页面坐标,,不过使用客户区坐标和滚动信息可以计算出来。这时候需要用到document.body(混杂模式) 或 doucment.documentElement(标准模式)中的scrollLef 和 scrollTop属性 属性就可以确定鼠标事件发生时鼠标指针相对于整个屏幕的坐标信息。 虽然鼠标事件主要是使用鼠标来触发的,但在按下鼠标时键盘上的牟谢建的状态也可以影响到所要采取的操作,这些键是Shift、Ctrl、Alt、Meta(windows键/Cmd键)。DOM为此规定了四个属性:shiftKey、ctrlKey、altKey、metaKey。这些属性中包含的都是布尔值,如果相应的键被按下了,则值为true,否则值为false。 在发生 mouseover 和 mouseout 事件时,还会涉及更多元素。这两个是事件都会涉及把鼠标指针从一个元素的边界之内移动到另一个元素的边界之内。 DOM 通过 event 对象的 relatedTarget 属性提供了相关元素的信息。这个属性只对于 mouseover、mouseout事件才包含值:对于其他事件,这个属性的值 null。IE8之前版本不支持这个属性(IE9支持),在mouseover事件触发的时候,IE的 formElement 属性中保存了相关元素;在mouseout 事件触发时,IE的 toElement属性中保存着相关元素。 只有在注释表按钮被单击(或键盘回车键按下)时才会触发 click 事件,对于 mousedown 和 mouseup 事件来说,则在其 event 对象存在一个 button 属性,表示按下或释放的按钮。DOM 的 button 属性可能有 如下 3个值: IE8及之前也提供了 与DOM button 有差异的 button 属性。 DOM模型下的 button 属性比IE模型下的 button 属性更简单也更为实用,常见的做法就是将IE模型规范华为DOM方法, “DOM2级事件” 规范在event 对象中还提供了 detail 属性,用于给出有关事件更多的信息。对于鼠标事件来说,detail 中包含了一个数值,表示在给定位置上发生了多少次单击。在同一元素上相继地发生一次 mousedown 和 mouseup 事件后算作一次单击。detail 属性从1 开始计数,每次单击发生后都会递增。如果鼠标在 mousedown 和 mouseup 之间移动了位置,则detail 会被重置为0 IE 6.0 首先实现了 mousewheel 事件。与 mousewheel事件对应的 event 对象除包含鼠标事件的所有标准信息外,还包含一个特性的wheelDelta属性。当向前滚动鼠标滚轮时,wheelDelta 是120的倍数;向后滚动鼠标滚轮时,wheelDelta 是 -120的倍数。 有一点需要注意:在 Opera 9.5 之前的版本中,wheelDelta 值的正负号是颠倒的。如果打算支持早期的 Opera 版本,就需要使用浏览器检测技术来确定实际的值, Firefox 支持一个名为 DOMMouseScroll 的类似事件,也是在鼠标滚轮滚动时触发。与mouseWhell事件一样,包含与鼠标事件有关的所有特性。有关鼠标滚轮的信息则保存在 detail 属性中,当向前滚动鼠标滚轮时,这个属性的值是 -3 的倍数,当向后滚动鼠标滚轮时,这个属性的值是 3 的倍数 要给出跨浏览器环境下的解决方案,第一步是创建一个能够取得鼠标滚轮增量值(delta)的方法。 iOS 和 Android 设备的实现非常特别,因为这些设备没有鼠标。在面向iPhone 和 iPad 中的 Safari 开发时,要记住以下几点 Web应用程序或网站要确保残疾人特别是那些使用屏幕阅读器的人能够访问,那么在使用鼠标事件时就要格外小心。通过键盘上的回车键可以触发 click 事件,但其它鼠标事件无法通过键盘来触发。为此,我们不建议使用 click 之外的其他鼠标事件来展示功能或引发代码执行。因为这样会给盲人或障碍用户造成极大不方便。以下是在使用鼠标事件时应该注意的几个易访问性问题。 用户在使用键盘时会触发键盘事件。“DOM3级事件”为键盘事件制定了规范,IE9率先完全实现了该规范。 此外还有一个文本事件:textInput。这个事件是对 keypress 的补充,用意是在将文本显示给用户之前更容易拦截文本。在文本插入文本框之前会触发 textInput 事件 在发生keydown、keyup事件时,event 对象的 keyCode 属性中会包含一个代码,与键盘上一个特定的键对应。DOM 和 IE 的 event对象都支持这个属性 在所有浏览器中,按下能够插入或删除字符的键都会触发 keypress 事件;按下其他键能否发次事件因浏览器而异。 尽管所有浏览器都实现了某种形式的键盘事件,DOM3级 事件做出了一些改变。比如,DOM3级事件中的键盘事件,不在包含 charCode 属性,而是包含两个新属性:key 和 code(已废弃) key 属性是为了取代 keyCode 而新增的,它的值是一个字符串。在线下非字符键时,key的值是相应键的名 DOM3级事件还添加了 location 属性,这是一个数值,表示按下了什么位置上的键 IE9支持这个属性。Safari 和 Chrome 支持名为 keyLocation 的等价属性,但有bug——值始终是 0,除非按下了数字键盘(3);否则,不会是1、2、4、5 getModifierState()方法。这个方法接收一个参数,即等于Shift、Control、AltGraph、Meta的字符串,表示要检测的修改键。如果指定的修改键是活动的(也就是处于被按下的状态),这个方法就会返回true,否则返回false “DOM3级事件” 规范中引入了一个新事件,名叫 textInput。当用户在可编辑区域中输入字符时,就会触发这个事件。这个事件与 keypress 之间有如下区别。 由于 textInput 事件主要考虑的是字符,因此它的 event 对象中还包含一个 data 属性,这个属性的值就是用户输入的字符。 任天堂Wii 会在用户按下 Wii 遥控器上的按键时触发键盘事件。尽管没有办法访问 Wii遥控器中所有案件,但还是有一些键可以触发事件。 当用户按下十字键盘(键码为175~178)、减号(170)、加号(174)、1(172)、2(173)键时就会触发键盘事件。但没有办法得知用户是否按下了电源开发、A、B或主页键 复合事件(composition event)是DOM3级事件中添加的一类事件,用于处理IME的输入序列IME(Input Method Editor,输入法编辑器)可以让用户输入在物理键盘上找不到的字符。 复合事件与文本事件在很多方法都很相似。在触发复合事件时,目标是接收文本的输入字段。但它比文本事件的事件对象多一个属性data,其中包含以下几个值中的一个: DOM2级 的变动(mutation)事件及能在DOM中的某一部分发生变化时给出提示。变动事件是为XML或 HTML DOM 设计的,并不特定于某种语言。DOM2级定义了如下变动事件 DOM 规范没有涵盖所以浏览器支持的所有事件。HTML5 详尽列出了浏览器应该支持的所有事件。本节只讨论其中得到浏览器玩上支持的事 用以表示何时应该显示上下文菜单(在浏览器中鼠标右键打开的菜单列表),以便开发人员取消默认的上下文菜单而提高自定义的菜单。 以上面的 HTML 结构为例 这个例子很简单,但它却展示了 Web 上所有自定义上下文菜单的基本结构。只需为这个例子中的上下文菜单添加一些css样式,就可以得到非常的效果 这个事件会在浏览器卸载页面之前触发,可以通过它来取消卸载并继续使用原有页面。但是,不能彻底取消这个事件,因为那就相当于让用户无法离开当前页面。为此,这个事件的意图是将控制权交给用户,显示的消息会告知用户页面将被卸载 DOMContentLoaded事件在形成完整的DOM树之后就会触发,不理会图像、JavaScript文件、CSS文件或其他资源是否下载完毕。与load事件不同,DOMContentLoaded 支持在页面下载的早期添加事件处理程序,这也就意味着用户能够尽早地与页面进行交互 提供与文档或元素的加载状态有关的信息,支持 readystatechange 事件的每个对象都有一个 readyState 属性,可能包含下列5个值中的一个。 为了尽可能抢到先机,有必要同时检测交互和完成阶段 此外,
导致 “空事件处理程序” 的另一种情况,就是卸载页面的时候。毫不奇怪,IE8及更早版本在这种情况下依然是问题最多的浏览器,经过其他浏览器或多或少也有类似的问题。在页面被卸载之前没有清理干净事件处理程序,那它们就会滞留在内存中。 可以使用 JavaScript 在任意时刻来触发特定的事件,而此时的事件就如同浏览器创建的事件一样。 在意在 document 对象上使用 createEvent() 方法创建 event 对象。MDN上面推荐 使用 event constructors来 代替这个方法。 createEvent() 这个方法接受一个参数,即表示要创建的事件类型的字符串。 为 createEvent() 传入字符串“MouseEvents”。返回的对象有一个名为 initMouseEvent() 方法,用于指定与该鼠标事件有关的信息。这个方法接受 15 个参数,分别与鼠标事件中每个典型的属性一一对应。 当把dispatchEvent() 方法时,这个对象 target属性会自动设置。 DOM3 级规定,调用 createEvent() 并传入 “KeyboardEvent” 就可以创建一个键盘事件。返回的事件对象包含一个 initKeyEvent() 方法,这个方法接受下列参数 这个例子模拟的是按住 Shift 的同时又 按下 A键 在 Firefox 中,调用 createEvent() 并传入“KeyEvents”就可以创建一个键盘事件。返回的事件对象会包含一个 initKeyEvent() 方法,这个方法接受下列 10个参数。 在 Firefox 中运行上面的代码,会在指定的文本框中输入字母A。统一,也可以依此模拟keyup 和 keydown 事件 虽然鼠标事件和键盘事件是在浏览器中最经常模拟的事件,但有时候同样需要模拟变动事件和HTML 事件。 模拟变动事件,可以使用 createEvent('MutationEvents') 创建一个包含 initMutationEvent() 方法的变动事件对象。这个方法接受的参数包括:type、bubbles、cancelable、relateNode、preValue、newValue、attrName、attrChange 要模拟HTML 事件,同样需要先创建一个 event对象——通过 createEvent("HTMLEvents"),然后再使用这个对象的initEvent() 方法来初始化它即可。 DOM3级 还定义了“自定义事件”。创建自定义事件,可以调用 createEvent('CustomEvent')返回的对象有一个名为 initCustomEvent()的方法,接受如下4个参数 IE8 及之前版本中模拟事件与在DOM中模拟事件的思路相似:先创建 event 对象,然后为期指定相应的信息,然后再使用该对象来触发事件。 document.createEventObject() 方法可以在IE中创建event 对象。这个方法不接受参数,结果会返回一个通用的 event 对象。然后,你必须为证对象添加所有必要的信息。最后一步就是在目标上调用 fireEvent() 方法,这个方法接受两个参数:事件处理程序的名称 和 event 对象。 采用同样的模式 也可以模拟 出发 keypress 事件 在使用事件时,需要考虑如下一些内存与性能方面的问题 事件时 JavaScript 中最重要的主题之一,深入理解事件的工作机制以及它们对性能的影响至关重要
以前面的HTML代码为例,当点击
"DOM2级事件" 规范明确要求捕获阶段不会涉及事件目标,但IE9、Safari、Chrome、Firefox、Opera9.5级更高版本都会在捕获阶段触发事件对象上的事件。结构,就是有两个机会在目标对象上面操作事件
二、事件处理程序
2.1、HTML事件处理程序
例如:在按钮被单击时执行一些JavaScript
事件处理程序中的代码在执行时,有权访问全局作用域中的任何代码
function() {
with(document) {
with(this) {
// 元素属性值
}
}
}
2.2、DOM0 级事件处理程序
var btn = document.getElementById('myBtn')
btn.onclick = function() {
alert('clicked')
}
btn.onclick = function() {
alert(this.id) // myBtn
}
以这种方式添加的事件处理程序会在事件流的冒泡阶段被处理
也可以删除通过DOM0 级方法指定的事件处理程序,只要像下面这样将事件处理程序属性的值设为null即可。btn.onclick = null // 删除事件处理程序
2.3、DOM2 级事件处理程序
例如为按钮添加 click 事件
‘var btn = document.getElmentById('myBtn')
btn.addEventListener('click', function() {
alert(this.id)
}, false)
var btn = document.getElementById('myBtn')
btn.addEventListener('click', function() {
alert(this.id)
}, false)
btn.addEventListener('click', function() {
alert('Nice to see you')
}, false)
这两个事件会依次触发,myBtn Nice to see you
btn.addEventListener('click', function() {
alert('Hello')
}, false)
btn.removeEventListener('click', function() { // 无效
alert('Hello')
}, false)
移除事件必须传入相同的 事件处理程序函数。如下:
var handle = function() {
alert('Hello')
}
btn.addEventListener('click', handle, false)
btn.removeEventListener('click', handle, false)
大多数情况下,都是将事件处理程序添加到事件流的冒泡阶段,这样可以最大限度的兼容各种浏览器。如果不是特别需要,不建议在事件捕获阶段注册事件处理程序
2.4、IE事件处理程序
(IE11废弃了下面的两个方法支持DOM标准,IE11以下都支持下面的两个方法,IE8及以下不支持DOM标准中提供的两个方法)
实现了与DOM中类似的两个方法:attachEvent()、deleteEvent()。这两个方法接受相同的两个参数:
由于IE8及更早版本只支持事件冒泡,所以通过 attachEvent() 添加的事件处理程序都会被添加到冒泡阶段
使用 attachEvent() 为按钮添加一个事件处理程序:
btn.attachEvent('onclick', function() {
alert('See you')
})
在使用DOM0 级方法的情况下,事件处理程序会在其所属元素的作用域内运行;
attachEvent() 方法的情况下,事件处理程序会在全局作用域中运行,因此 this 等于 window。btn.attachEvent('onclick', function() {
alert(this === window) // true
})
btn.attachEvent('onclick', function() {
alert('clicked')
})
btn.attachEvent('onclick', function() {
alert('****')
})
以上会先看到 **** 然后看到 clicked
var handle = function() {
alert('Hello')
}
btn.attachEvent('onclick', handle)
btn.detachEvent('onclick', handle)
2.5、跨浏览器的事件处理程序
根据 DOM 和 IE 封装兼容函数,如下
var EventUtil = {
addHandler: function(element, type, handler) {
if (element.addEventListener) { // 支持 addEventListener
element.addEventListener(type, handler, false)
}else if (element.attachEvent) { // IE
element.attachEvent('on' + type, handler)
} else { // 都不支持的情况下,默认使用 DOM0 级
element['on' + type] = handler
}
},
removeHandler: function(element, type, handler) {
if (element.removeEventListener) { // 支持 DOM
element.removeEventListener(type, handler, false)
} else if (element.detachEvent) { // IE
element.detachEvent('on' + type, handler)
} else {
element['on' + type] = null
}
}
}
var btn = document.getElementById('myBtn')
var handler = function() {
alert('Hello')
}
// 注册事件
EventUtil.addHandler(btn, 'click', handler)
// 移除事件
EventUtil.removeHandler(btn, 'click', handler)
此外还需要注意,DOM0 级对每个事件只支持一个事件处理程序。不过只支持DOM0 级的浏览器已经几乎灭绝了,所以不是上面问题
三、事件对象
3.1、DOM中的事件对象
var btn = document.getElementById('myBtn')
btn.onclick = function(event) {
alert(event.type) // click
}
btn.addEventListener('click', function(event) {
alert(event.type) // click
}, false)
属性/方法
类型
读写
说明
bubbles
Boolean
只读
表明事件是否冒泡
cancelable
Boolean
只读
表明是否可以取消事件的默认行为
currentTarget
Element
只读
其他事件处理程序当前正在处理事件的那个元素
defaultPrevented
Boolean
只读
为true表示已经调用了 preventDefault()
detail
Integer
只读
与事件相关的细节信息
eventPhase
Integer
只读
调用事件处理程序的阶段:1表示捕获阶段,2表示处于目标阶段,3表示处于冒泡阶段
preventDefault()
Function
只读
取消事件的默认行为。如果cancelable是true,则可以使用这个方法
stopImmediatePropagation()
Function
只读
取下事件的进一步捕获或冒泡,同时阻止任何事件处理程序被调用
stopPropagation()
Function
只读
取消事件的进一步捕获或冒泡。如果bubbles 为 true,则可以使用这个方法
target
Element
只读
事件的目标
trusted
Boolean
只读
为true表示事件是浏览器生成的。为false表示事件是由开发人员通过JavaScript创建的
type
String
只读
被触发的事件类型
view
Abstractview
只读
与事件关联的抽象视图。等同于发生事件的window对象
var btn = document.getElementById('btn')
btn.onclick = function (event) {
console.log(event.currentTarget === this) // true
console.log(event.target === this) // true
}
var btn = document.getElementById('myBtn')
var handler = function(event) {
switch (event.type) {
case 'click':
alert('clicked')
break;
case 'mouseover':
event.target.style.backgroundColor = 'red'
break;
case 'mouseout':
event.target.style.backgroundColor = ''
break;
}
}
btn.onclick = handler
btn.onmouseover = handler
btn.onmouseout = handler
例如,取消链接的默认行为
var link = document.getElementsByTagName('a')[0]
link.onclick = function(event) {
event.preventDefault() // 取消默认行为
// todo
}
只有 cancelable 属性设置为 true的事件,才可以使用preventDefault() 来取消其默认行为。
var btn = document.getElementById('myBtn')
btn.onclick = function(event) {
alert('clicked')
event.stopPropagation() // 阻止冒泡
}
document.body.onclick = function(event) {
alert('Body clicked')
}
当点击 btn 的时候,只会触发 btn的点击事件,而不会通过冒泡同时去触发 body 的click事件
需要注意的是,尽管”处于目标阶段“发生在冒泡阶段,但 eventPhase 仍然会等于2
var btn = document.getElementById('myBtn')
btn.onclick = function (event) {
alert (event.eventPhase) // 2
}
document.body.addEventListener('click', function(event) {
alert(event.eventPhase) // 1
}, true) // 设置为 事件捕获
document.body.onclick = function (event) {
alert(event.eventPhase)
}
3.2、IE中的事件对象(IE8-)
var btn = document.getElementById(myBtn')
btn.onclick = function() {
var event = window.event
alert(event.type)
}
var btn = document.getElementById('myBtn')
btn.attachEvent('onclick', function(event) {
alert(event.type) // click
})
属性/方法
类型
读/写
说明
cancelBubble
Boolean
读/写
默认值为false,但将其设置为 true 就可以取消事件冒泡(与DOM中的 stopPropagation() 方法的作用相同 )
returnValue
Boolean
读/写
默认值为 true,但将其设置为 false 就可以取消事件的默认行为(与 DOM 中的 preventDefault() 方法的作用相同 )
srcElement
Element
只读
事件的目标(与DOM中的target属性相同)
type
String
只读
被触发的事件的类型
var btn = document.getElement('myBtn')
btn.onclick = function() {
alert(window.event.srcElement === this) // true
}
btn.attachEvent('onclick', function(event) {
alert(event.srcElement === this) // false
})
var link = document.getElementsByTagName('a')[0]
link.onclick = function() {
window.event.returnValue = false
}
var btn = document.getElementById('myBtn')
btn.onclick = function() {
alert('clicked')
window.event.cancelBubble = true
}
document.body.onclick = function() {
alert('Body clicked')
}
3.3、跨浏览器的事件对象
var EventUtil = {
// 注册事件
addHandler: function(element, type, handler) {
if (element.addEventListener) { // 支持 addEventListener
element.addEventListener(type, handler, false)
}else if (element.attachEvent) { // IE
element.attachEvent('on' + type, handler)
} else { // 都不支持的情况下,默认使用 DOM0 级
element['on' + type] = handler
}
},
// 移除事件
removeHandler: function(element, type, handler) {
if (element.removeEventListener) { // 支持 DOM
element.removeEventListener(type, handler, false)
} else if (element.detachEvent) { // IE
element.detachEvent('on' + type, handler)
} else {
element['on' + type] = null
}
},
// 获取 event 对象
getEvent: function(event) {
return event ? event : window.event
},
// 获取目标元素
getTarget: function(event) {
return event.target || event.srcElement
},
// 阻止默认行为
preventDefault: function(event) {
if (event.preventDefault) {
event.preventDefault()
} else {
event.returnValue = false
}
},
// 阻止冒泡
stopPropagation: function(event) {
if (event.stopPropagation) {
event.stopPropagation()
} else {
event.cancelBubble = true
}
}
}
使用
点我
当点击 a 标签的时候,不会触发 body 的点击事件。只会输出 'clicked' 及 'A'(标签名)
四、事件类型
4.1、UI 事件
var isSupportedDOM2Event = document.implementation.hasFeature('HTMLEvents', '2.0')
var isSupportedDOM3Event = document.implementation.hasFeature('UIEvent', '3.0')
4.1.1、load事件
EventUtil.addHandler(window, 'load', function() {
alert('loaded!')
})
在HTML中为任何图像指定onload事件处理程序
使用 JavaScript 实现
var img = document.getElementsByTagName('img')[0]
EventUtil.addHandler(img, 'load', function(event) {
event = EventUtil.getEvent(event)
alert(EventUtil.getTarget(event).src)
})
EventUtil.addHandler(window, 'load', function() {
var image = document.createElement('img')
EventUtil.addHandler(image, 'load', function(event) {
event = EventUtil.getEvent(event)
alert(EventUtil.getTarget(event).src)
})
document.body.appendChild(image)
image.src='smile.gif'
})
新图像元素不一样要从添加到文档后才开始下载,只要设置了 src 属性 就会开始下载。
EventUtil.addHandler(window, 'load', function() {
var image = new Image()
EventUtil.addHandler(image, 'load', function(event) {
alert('Image loaded!')
})
image.src = 'smile.gif'
})
EventUtil.addHandler(window, 'load', function() {
// script 元素
var script = document.createElement('script')
EventUtil.addHandler(script, 'load', function(event) {
console.log('js loaded!')
})
script.src = 'example.js'
document.body.appendChild(script)
// link 元素
var link = document.createElement('link')
link.type = 'text/css'
link.rel = 'stylesheet'
EventUtil.addHandler(link, 'load', function(event) {
console.log('css loaded!')
})
link.href = 'example.css'
document.getElementsByTagName('head')[0].appendChild(link)
})
4.1.2、unload 事件
EventUtil.addHandler(window, 'unload', function(event) {
alert('unload')
})
与 load事件 一样,也可以 通过为 元素 添加 onunload 特性
4.1.3 resize 事件
EventUtil.addHandler(window, 'resize', function(event) {
console.log('onresize')
})
resize事件 可能会被频繁执行注意性能
4.1.4、scroll 事件
EventUtil.addHandler(window, 'scroll', function(event) {
console.log( document.body ? document.body.scrollTop : document.documentElement.scrollTop)
})
与resize 事件象实,scroll 事件也会在文档被滚动期间重复被触发,所以有必要尽量保持事件处理程序的代码简单
4.2 焦点事件
var isSupported = document.implementation.hasFeature('FocusEvent', '3.0')
4.3、鼠标与滚轮事件
页面上的所有元素都支持鼠标事件。处理mouseenter 和 mouseleave,所有鼠标事件都会冒泡,也可以被取消,而取消鼠标事件将会影响浏览器的默认行为。取消鼠标事件的默认行为还会影响其他事件,因为鼠标事件与其他事件是密不可分的关系。
click 和 dbclick 事件都会依赖于其他先行事件的触发;而 mousedown 和 mouseup 则不受其他事件的影响。IE8及之前有一个 bug,在双击事件中,会跳过第二个mousedown 和 click 事件,IE9修复了这个bug
var isSupported = document.implementation.hasFeature('MouseEvent', '3.0')
4.3.1、客户区坐标位置
var div = document.getElementById('myDiv')
EventUtil.addHandler(div, 'click', function(event) {
event = EventUtil.getEvent(event)
console.log(event.clientX, event.clientY)
})
4.3.2、页面坐标位置
var div = document.getElementById('div')
EventUtil.addHandler(div, 'click', function(event) {
event = EventUtil.getEvent(event)
console.log(event.pageX, event.pageY)
})
var div = document.getElementById('div')
EventUtil.addHandler(div, 'click', function(event) {
event = EventUtil.getEvent(event)
var pageX = event.pageX
var pageY = event.pageY
if (pageX === undefined) {
pageX = event.clienX + (document.body.scrollLeft || document.documentElement.scrollLeft)
}
if (pageY === undefined) {
pageY = event.clientY + (document.body.scrollTop || document.documentElement.scrollTop)
}
console.log(pageX, pageY)
})
4.3.3、屏幕坐标位置相对于电脑屏幕的位置。通过 screenX 和 screenY
var div = document.getElementById('div')
EventUtil.addHandler(div, 'click', function(event) {
event = EventUtil.getEvent(event)
console.log(event.screenX, event.screenY)
})
4.3.4 修改键
var div = document.getElementById('div')
EventUtil.addHandler(div, 'click', function(event) {
event = EventUtil.getEvent(event)
var keys = new Array()
if (event.shiftKey) { // shift
keys.push('shift')
}
if(event.ctrlKey) { // ctrl
keys.push('ctrl')
}
if(event.altKey) { // alt
keys.push('alt')
}
if (event.metaKey) { // meta
keys.push('meta')
}
console.log(keys.join(', '))
})
IE8及之前不支持 metaKey 属性
4.3.5、相关元素
如上,如果鼠标指针一开始位于这个
将相关元素的方法添加到 EventUtil 对象中
var EventUtil = {
getRelatedTarget: function(event) {
if (event.relatedTarget) {
return event.relatedTarget
} else if (event.toElement) {
return event.toElement
} else if (event.fromElement) {
return event.fromElement
} else {
return null
}
}
}
可以像下面这样去使用 EventUtil.getRelatedTarget() 这个方法
var div = document.getElementById('div')
EventUtil.addHandler(div, 'mouseout', function(event) {
event = EventUtil.getEvent(event)
var target = EventUtil.getTarget(event)
var relatedTarget = EventUtil.getRelatedTarget(event)
console.log('Moused out of ' + target.tagName + ' to ' + relatedTarget.tagName)
})
4.3.6、鼠标事件
由于单独使用能力监测无法确定差异(两种模型有同名的button属性),因此必须另辟蹊径,我们知道,支持DOM版鼠标事件的浏览器可以通过hasFeature()方法监测,所以可以再为 EventUtil 对象 添加如下的 getButton() 方法。
var EventUtil = {
// 省略了其他代码
getButton: function(event) {
if (document.implementation.hasFeature('MouseEvents', '2.0')) { // 支持 Dom 版
return event.button
} else { // IE 低版本
switch(event.button) {
case 0:
case 1:
case 3:
case 5:
case 7:
return 0
case 2:
case 6:
return 2
case 4:
return 1
}
}
}
}
使用该方法的实例:
var div = document.getElementById('div')
EventUtil.addHandler(div, 'mousedown', function(event) {
event = EventUtil.getEvent(event)
var button = EventUtil.getButton(event)
console.log(button)
})
在
4.2.7、更多的事件信息
IE 也通过下列属性为鼠标事件提供更多信息。
这些属性的用处并不大,原因一方面只是有IE支持他们,另一方面它们提供的信息要么 没有什么价值,要么可以通过其他方式计算得来。
4.3.8、鼠标滚轮事件
EventUtil.addHandler(document, 'mousewheel', function(event) {
event = EventUtil.getEvent(event)
console.log(event.wheelDelta)
})
多数情况下,只要知道鼠标滚轮滚动的方向就够了,而这通过检测 wheelDelta 的正负号就可以确定。
// ...
var delta = (client.engine.opera && client.engine.opera < 9.5 ? -event.wheelDelta : event.wheelDelta)
上面用到的 client, 在前面的客户端检测中有提到,检测浏览器是不是早前的 Opera
EventUtil.addHandler(document, 'DOMMouseScroll', function(event) {
event = EventUtil.getEvent(event)
console.log(event.detail)
})
测试后返回的 7(向下) 和 -7(向上)
// 获取 鼠标滚轮 增量值 (delta)
getWheelDelta: function(event) {
var detail = 0
if (event.wheelDelta) {
detail = client.engine.opera && client.engine.opera < 9.5 ? -event.wheelDelta : event.wheelDelta
} else {
detail = -event.detail
}
return detail > 0 ? -1 : 1
}
由于在实际测试时,两个属性给出的值飘忽不定,所以这里只返回 -1 或 1 编码滚动的方法即可,-1代表向 页面向下滚动, 1 代表页面向上滚动
使用var mouseWheelHandler = function(event) {
event = EventUtil.getEvent(event)
var delta = EventUtil.getWheelDelta(event)
console.log(delta)
}
EventUtil.addHandler(document, 'DOMMouseScroll',mouseWheelHandler)
EventUtil.addHandler(document, 'mousewheel'mouseWheelHandler)
如上:在多个浏览器下,都会有一致的返回结果
4.3.9、触摸设备
4.3.10、无障碍性问题
遵照以上提示可以极大地提升残疾人在访问你的 Web 应用程序或网站时的 易访问性
4.4、键盘与文本事件
有3个键盘事件,简述如下
按下Esc 键也会触发这个事件。Safari 3.1之前的版本也会在用户按下非字符键时触发 keypress 事件。
虽然所有元素都支持以上3个元素,但只有在用户通过文本框输入时才最常用到
如果用户按下一个字符键不放,就会重复触发 keydown 和 keypress 事件,直到用户松开改建为止。
如果按住这个非字符键不放,那么就会一直重复触发 keydow 事件
4.4.1、键码
var textBox = document.getElementById('myText')
EventUtil.addHandler(textbox, 'keydown', function(event) {
event = EventUtil.getEvent(event)
console.log(event.keyCode)
})
无论是 keydown 或 keyup 事件都会存在一些特殊情况。在Firefox 和 Opera 中,按分号键时 keyCode 值为 59,也就是 ASCII 中分号的编码;但IE 和 Safari 返回 186,即键盘中按键的键码。
4.4.2、字符编码
IE9、Firefox、Chrome、Safari 的 event 对象都支持一个 charCode 属性,这个属性只有在发生 keypress 事件时才包含值,这个值是按下的那个键所代表字符的 ASCII 编码。此时的 keyCode 通常等于 0 或者 也可能等于所按键的键码。IE8及之前版本和 Opera 则是在 KeyCode 中保存字符的 ASCII 编码。
以跨浏览器的方式取得字符编码
var EventUtil = {
// ...
getCharCode: function(event) {
if (typeof event.charCode == 'number') {
return event.charCode
} else {
return event.keyCode
}
}
}
使用这个方法
var textbox = document.getElementById('myText')
EventUtil.addHandler(textbox, 'keypress', function(event) {
event = EventUtil.getEvent(event)
console.log(event.keyCode)
console.log(event.charCode)
})
在取得了字符编码之后,就可以使用 String.fromCharCode() 将其转换成实际的字符。
4.4.3、DOM3 级变化
由于跨浏览器问题,目前不是推荐使用 key(兼容问题)、keyIdentifier(已弃用)、char(已弃用),在MDN上同时提到 keyCode 也不推荐使用,并给出了如下的推荐代码
window.addEventListener("keydown", function (event) {
if (event.defaultPrevented) { // 检测是否设置了 preventDefault()
return; // Should do nothing if the default action has been cancelled
}
var handled = false;
if (event.key !== undefined) { // 支持 key
// Handle the event with KeyboardEvent.key and set handled true.
} else if (event.keyCode !== undefined) { // 支持 keyCode
// Handle the event with KeyboardEvent.keyCode and set handled true.
}
if (handled) { // 都不支持
// Suppress "double action" if event handled
event.preventDefault();
}
}, true);
var textbox = document.getElementById('myText')
EventUtil.addHandler(textbox, 'keypress', function(event) {
event = EventUtil.getEvent(event)
var loc = (typeof event.location === 'number') ? event.location : event.keyLocation
if (typeof loc === 'number') {
console.log(loc)
}
})
与 key 属性一样,支持 location的浏览器也不多,所以在跨浏览器开发中不推荐使用。
var textbox = document.getElementById('myText')
EventUtil.addHandler(textbox, 'keypress', function(event) {
event = EventUtil.getEvent(event)
if (event.getModifierState) {
console.log(event.getModifierState('Shift'))
}
})
实际上,通过 event 对象的 shiftKey、altKey、ctrlKey、metaKey属性以及可以取得类似的属性了。
4.4.4、textInput 事件
var textbox = document.getElementById('myText')
EventUtil.addHandler(textbox, 'textInput', function(event) {
event = EventUtil.getEvent(event)
console.log(event.data)
})
event 对象上还有一个属性,叫 inputMethod(查不到,应该是废弃了),表示把文本输入到文本框中的方式
4.4.5、设备中的键盘事件
4.5、复合事件
有以下三种复合事件
var textbox = document.getElementById('myText')
EventUtil.addHandler(textbox, 'compositionstart', function(event) {
event = EventUtil.getEvent(event)
console.log(event.data)
})
EventUtil.addHandler(textbox, 'compositionupdate', function(event) {
event = EventUtil.getEvent(event)
console.log(event.data)
})
EventUtil.addHandler(textbox, 'compositionend', function(event) {
event = EventUtil.getEvent(event)
console.log(event.data)
})
这个方法有一定的兼容问题,低版本浏览器大多不支持,可以使用以下代码检测浏览器是否支持复合事件
var isSupported = document.implementation.hasFeature('CompositionEvent', '3.0')
4.6、变动事件
这些方法在不久的将来会废弃,所以不推荐使用了。这里简单的提一下
4.7、HTML5事件
4.7.1、contextmenu 事件
这个事件的目标是发生用户操作的元素。在所有浏览器中都可以取消这个事件:在兼容DOM的浏览器中,使用 event.preventDefault();在IE中,将event.returnValue 的值设置为false
var div = document.getElementById('myDiv')
EventUtil.addHandler(div, 'contextmenu', function(event) {
event = EventUtil.getEvent(event)
EventUtil.preventDefault(event) // 取消默认行为 不显示默认菜单
var menu = document.getElementById('myMenu')
// 定位
menu.style.left = event.clientX + 'px'
menu.style.top = event.clientY + 'px'
// 显示菜单
menu.style.visibility = 'visible'
})
EventUtil.addHandler(document, 'click', function(event) {// 隐藏菜单
document.getElementById('myMenu').style.visibility = 'hidden'
})
4.7.2、beforeunload 事件
为了显示对话框,提示用户,必须将 event.returnValue 的值设置为要显示给用户的字符串(对IE及Firefox而言),同时作为函数的值返回(对Safari和Chrome)
EventUtil.addHandler(window, 'beforeunload', function(event) {
event = EventUtil.getEvent(event)
var message = 'are you sure'
event.returnValue = message
return message
})
4.7.3、DOMContentLoaded 事件
可以为 document 或 window 添加相应的事件处理程序(尽管这个事件会冒泡到 window,但它的目标实际上是 document)
EventUtil.addHandler(window, 'DOMContentLoaded', function(event) {
alert('Content loaded')
})
这个事件始终都会在load事件之前触发,支持这个属性的有 IE9+、Firefox、Chrome、Safari3.1+、Opera9+
4.7.4、readystatechange 事件
但并非所有对象都会经历 readyState 的这几个阶段。如果某个阶段不适用某个对象,则该对象完全可能跳过该阶段;
对于 document 而言,值为"interactive"的 readyState 会在与 DOMContentLoaded 大致相同的时刻触发 readystatechange 事件。此时,DOM数已经加载完毕,可以安全操作它了,因此就会进入交互(interactive)阶段。EventUtil.addHandler(document, 'readystatechange', function(event) {
if (document.readyState == 'interactive' ) alert('Content loaded')
})
EventUtil.addHandler(document, 'readystatechange', function(event) {
if (document.readyState == 'interactive' || document.readyState == 'complete') {
EventUtil.removeHandler(document, 'readystatechange', arguments.callee)
alert('Content loaded')
}
})
当 readystatechange事件触发时,会检测 document.readyState 的值,看当前是否已经进入交互阶段或完成阶段。如果是,则移除相应的事件处理程序以及在其他阶段再执行。
这样就确保了内存可以被 ,再次利用,而从 DOM 中移除按钮也做到了干净利索。
最好的做法是在页面卸载之前,先通过 onunload 事件处理程序移除所有事件处理程序。在此,事件委托技术再次表现出它的优势——需要跟踪的事件处理程序越少,移除他们就越容易。对这种类似撤销的操作,我们可以把它想象成:只要是通过 onload 事件处理程序添加的东西,最后都要通过 onunload 事件处理程序将他们移除。六、模拟事件
6.1、DOM中的事件模拟
这个字符串可以是下列字符串之一
6.1.1、模拟鼠标事件
这些参数的含义如下:
var btn = document.getElementById('myBtn')
// 创建事件对象
var event = document.createEvent('MouseEvents')
// 初始化事件对象
event.initMouseEvent('click', true, true, document.defaultView, 0, 0, 0, 0,
0, false, false, false, false, 0, null)
// 触发事件
btn.dispatchEvent(event)
6.1.2、模拟键盘事件
由于 DOM3级不提倡使用 keypress 事件,因此只能利用这种技术来模拟 keydown 和 keyup 事件。
var textbox = document.getElementById('myTextbox'), event
// 以DOM3 级方式创建事件对象
if (document.implementation.hasFeature('KeyboardEvents', '3.0')) {
event = document.createEvent('KeyboardEvent')
// 初始化事件对象
event.initKeyboardEvent('keydown', true, true, document.defaultView, 'a', 0, 'shift', 0)
}
console.log(event)
// 触发事件
textbox.dispatchEvent(event)
将创建event 对象传入到 dispatchEvent() 方法就可以出发键盘事件,如下:
// 只适用于Firefox
var textbox = document.getElementById('myTextbox')
// 创建事件对象
var event = document.createEvent('KeyEvents')
// 初始化事件对象
event.initKeyEvent('keypress', true, true, document.defaultView, false, false, false, false, 65, 65)
// 触发事件
textbox.dispatchEvent(event)
在其它浏览器中,则需要创建一个通用的事件,然后再向事件对象中添加键盘事件特有的信息。例如:var textbox = document.getElementById('myTextbox')
// 创建事件对象
var event = document.createEvent('Events')
// 初始化事件对象
event.initEvent(type, bubbles, cancelable)
event.view = document.defaultView
event.altKey = false
event.ctrlKey = false
event.shiftKey = false
event.metaKey = false
event.keyCode = 65
event.charCode = 65
// 触发事件
textbox.dispatchEvent(event)
6.1.3、模拟其他事件
模拟变动事件
var event = document.createEvent('HTMLevents')
event.initMutationEvent('DOMNodeeInserted', true, false, someNode, '', '', '', 0)
target.dispatchEvent(event)
var event = document.createEvent('HTMLEvents')
even.initEvent('focus', true, false)
target.dispatchEvent(event)
这个例子展示了如何在给定目标上模拟 focus 事件。模拟其他HTML事件的方法也是这样
6.1.4、自定义DOM事件
可以像分派其他事件一样在 DOM中分派创建的自定义事件对象。例如:
var div = document.getElementById('myDiv'), event
EventUtil.addHandler(div, "myevent", function(event) {
alert("DIV:" + event.detail)
})
EventUtil.addHandler(document, "myevent", function(event) {
alert("DOCUMENT:" + event.detail)
})
if (document.implementation.hasFeature("CustomEvents", "3.0")) {
event = document.createEvent("CustomEvent")
event.initCustomEvent("myevent", true, false, "Hello world!")
div.dispatchEvent(event)
}
6.2、IE中时事件模拟
在调用 fireEvent() 方法时,会自动为event 对象添加 srcElement 和 type 属性;模拟在一个按钮上触发click 事件过程
var btn = document.getElementById('myBtn')
// 创建事件对象
var event = document.createEventObject()
// 初始化事件对象
event.screenX = 100
event.screenY = 0
event.clientX = 0
event.clientY = 0
event.ctrlKey = false
event.altKey = false
event.shiftKey = false
event.button = 0
// 触发事件
btn.fireEvent("onclick", event)
var textbox = document.getElementById('myTextbox')
// 创建事件对象
var event = document.createEventObject()
// 初始化事件对象
event.ctrlKey = false
event.altKey = false
event.shiftKey = false
event.keyCode = 65
// 触发事件
textbox.fireEvent('onkeypress', event)
其实,目前来说新出来了很多API用于模拟事件,比如 click() 方法,所以这些都很少见了
七、小结