事件,就是网页中某个特别值得关注的瞬间。事件经常由用户操作或通过其他浏览器功能来触发。
但很少有人知道,也可以使用JavaScript 在任意时刻来触发特定的事件,而此时的事件就如同浏览器创建的事件一样。也就是说,这些事件该冒泡还会冒泡,而且照样能够导致浏览器执行已经指定的处理它们的事件处理程序。在测试Web 应用程序,模拟触发事件是一种极其有用的技术。DOM2 级规范为此规定了模拟特定事件的方式,IE9、Opera、Firefox、Chrome 和Safari 都支持这种方式。IE 有它自己模拟事件的方式。

13.6.1 DOM中的事件模拟

可以在document 对象上使用createEvent()方法创建event 对象。这个方法接收一个参数,即表示要创建的事件类型的字符串。在DOM2 级中,所有这些字符串都使用英文复数形式,而在DOM3级中都变成了单数。这个字符串可以是下列几字符串之一。

  • UIEvents:一般化的UI 事件。鼠标事件和键盘事件都继承自UI 事件。DOM3 级中是UIEvent。
  • MouseEvents:一般化的鼠标事件。DOM3 级中是MouseEvent。
  • MutationEvents:一般化的DOM 变动事件。DOM3 级中是MutationEvent。
  • HTMLEvents:一般化的HTML 事件。没有对应的DOM3 级事件(HTML 事件被分散到其他类别中)。

要注意的是,“DOM2 级事件”并没有专门规定键盘事件,后来的“DOM3 级事件”中才正式将其作为一种事件给出规定。IE9 是目前唯一支持DOM3 级键盘事件的浏览器。不过,在其他浏览器中,在现有方法的基础上,可以通过几种方式来模拟键盘事件。
在创建了event 对象之后,还需要使用与事件有关的信息对其进行初始化。每种类型的event 对象都有一个特殊的方法,为它传入适当的数据就可以初始化该event 对象。不同类型的这个方法的名字也不相同,具体要取决于createEvent()中使用的参数。
模拟事件的最后一步就是触发事件。这一步需要使用dispatchEvent()方法,所有支持事件的DOM 节点都支持这个方法。调用dispatchEvent()方法时,需要传入一个参数,即表示要触发事件的event 对象。触发事件之后,该事件就跻身“官方事件”之列了,因而能够照样冒泡并引发相应事件处理程序的执行。

1. 模拟鼠标事件

创建新的鼠标事件对象并为其指定必要的信息,就可以模拟鼠标事件。创建鼠标事件对象的方法是为createEvent()传入字符串"MouseEvents"。返回的对象有一个名为initMouseEvent()方法,用于指定与该鼠标事件有关的信息。这个方法接收15 个参数,分别与鼠标事件中每个典型的属性一一对应;这些参数的含义如下。

  • type(字符串):表示要触发的事件类型,例如"click"。
  • bubbles(布尔值):表示事件是否应该冒泡。为精确地模拟鼠标事件,应该把这个参数设置为true。
  • cancelable(布尔值):表示事件是否可以取消。为精确地模拟鼠标事件,应该把这个参数设置为true。
  • view(AbstractView):与事件关联的视图。这个参数几乎总是要设置为document.defaultView。
  • detail(整数):与事件有关的详细信息。这个值一般只有事件处理程序使用,但通常都设置为0。
  • screenX(整数):事件相对于屏幕的X 坐标。
  • screenY(整数):事件相对于屏幕的Y 坐标。
  • clientX(整数):事件相对于视口的X 坐标。
  • clientY(整数):事件想对于视口的Y 坐标。
  • ctrlKey(布尔值):表示是否按下了Ctrl 键。默认值为false。
  • altKey(布尔值):表示是否按下了Alt 键。默认值为false。
  • shiftKey(布尔值):表示是否按下了Shift 键。默认值为false。
  • metaKey(布尔值):表示是否按下了Meta 键。默认值为false。
  • button(整数):表示按下了哪一个鼠标键。默认值为0。
  • relatedTarget(对象):表示与事件相关的对象。这个参数只在模拟mouseover 或mouseout时使用。

显而易见,initMouseEvent()方法的这些参数是与鼠标事件的event 对象所包含的属性一一对应的。其中,前4 个参数对正确地激发事件至关重要,因为浏览器要用到这些参数;而剩下的所有参数只有在事件处理程序中才会用到。当把event 对象传给dispatchEvent()方法时,这个对象的target属性会自动设置。下面,我们就通过一个例子来了解如何模拟对按钮的单击事件。

  1. var btn = document.getElementById("myBtn");
  2. //创建事件对象
  3. var event = document.createEvent("MouseEvents");
  4. //初始化事件对象
  5. event.initMouseEvent("click", true, true, document.defaultView, 0, 0, 0, 0, 0,
  6. false, false, false, false, 0, null);
  7. //触发事件
  8. btn.dispatchEvent(event);

运行一下
在兼容DOM的浏览器中,也可以通过相同的方式来模拟其他鼠标事件(例如dblclick)。

2. 模拟键盘事件

前面曾经提到过,“DOM2 级事件”中没有就键盘事件作出规定,因此模拟键盘事件并没有现成的思路可循。“DOM2 级事件”的草案中本来包含了键盘事件,但在定稿之前又被删除了;Firefox 根据其草案实现了键盘事件。需要提请大家注意的是,“DOM3 级事件”中的键盘事件与曾包含在“DOM2 级事件”草案中的键盘事件有很大区别。
DOM3 级规定,调用createEvent()并传入"KeyboardEvent"就可以创建一个键盘事件。返回的事件对象会包含一个initKeyEvent()方法,这个方法接收下列参数。

  • type(字符串):表示要触发的事件类型,如"keydown"。
  • bubbles(布尔值):表示事件是否应该冒泡。为精确模拟鼠标事件,应该设置为true。
  • cancelable(布尔值):表示事件是否可以取消。为精确模拟鼠标事件,应该设置为true。
  • view (AbstractView ):与事件关联的视图。这个参数几乎总是要设置为document.defaultView。
  • key(布尔值):表示按下的键的键码。
  • location(整数):表示按下了哪里的键。0 表示默认的主键盘,1 表示左,2 表示右,3 表示数字键盘,4 表示移动设备(即虚拟键盘),5 表示手柄。
  • modifiers(字符串):空格分隔的修改键列表,如"Shift"。
  • repeat(整数):在一行中按了这个键多少次。

由于DOM3级不提倡使用keypress 事件,因此只能利用这种技术来模拟keydown 和keyup 事件。

  1. var textbox = document.getElementById("myTextbox"),
  2. event;
  3. //以DOM3 级方式创建事件对象
  4. if (document.implementation.hasFeature("KeyboardEvents", "3.0")) {
  5. event = document.createEvent("KeyboardEvent");
  6. //初始化事件对象
  7. event.initKeyboardEvent("keydown", true, true, document.defaultView, "a", 0, "Shift", 0);
  8. }
  9. //触发事件
  10. textbox.dispatchEvent(event);

运行一下
这个例子模拟的是按住Shift 的同时又按下A 键。在使用document.createEvent
("KeyboardEvent")之前,应该先检测浏览器是否支持DOM3 级事件;其他浏览器返回一个非标准的KeyboardEvent 对象。
在Firefox 中,调用createEvent()并传入"KeyEvents"就可以创建一个键盘事件。返回的事件对象会包含一个initKeyEvent()方法,这个方法接受下列10 个参数。

  • type(字符串):表示要触发的事件类型,如"keydown"。
  • bubbles(布尔值):表示事件是否应该冒泡。为精确模拟鼠标事件,应该设置为true。
  • cancelable(布尔值):表示事件是否可以取消。为精确模拟鼠标事件,应该设置为true。
  • view(AbstractView):与事件关联的视图。这个参数几乎总是要设置为document.default-View。
  • ctrlKey(布尔值):表示是否按下了Ctrl 键。默认值为false。
  • altKey(布尔值):表示是否按下了Alt 键。默认值为false。
  • shiftKey(布尔值):表示是否按下了Shift 键。默认值为false。
  • metaKey(布尔值):表示是否按下了Meta 键。默认值为false。
  • keyCode(整数):被按下或释放的键的键码。这个参数对keydown 和keyup 事件有用,默认值为0。
  • charCode(整数):通过按键生成的字符的ASCII 编码。这个参数对keypress 事件有用,默认值为0。

将创建的event 对象传入到dispatchEvent()方法就可以触发键盘事件,如下面的例子所示。

  1. //只适用于Firefox
  2. var textbox = document.getElementById("myTextbox")
  3. //创建事件对象
  4. var event = document.createEvent("KeyEvents");
  5. //初始化事件对象
  6. event.initKeyEvent("keypress", true, true, document.defaultView, false, false,
  7. false, false, 65, 65);
  8. //触发事件
  9. textbox.dispatchEvent(event);

运行一下
在Firefox 中运行上面的代码,会在指定的文本框中输入字母A。同样,也可以依此模拟keyup 和keydown 事件。
在其他浏览器中,则需要创建一个通用的事件,然后再向事件对象中添加键盘事件特有的信息。
例如:

  1. var textbox = document.getElementById("myTextbox");
  2. //创建事件对象
  3. var event = document.createEvent("Events");
  4. //初始化事件对象
  5. event.initEvent(type, bubbles, cancelable);
  6. event.view = document.defaultView;
  7. event.altKey = false;
  8. event.ctrlKey = false;
  9. event.shiftKey = false;
  10. event.metaKey = false;
  11. event.keyCode = 65;
  12. event.charCode = 65;
  13. //触发事件
  14. textbox.dispatchEvent(event);

以上代码首先创建了一个通用事件,然后调用initEvent()对其进行初始化,最后又为其添加了键盘事件的具体信息。在此必须要使用通用事件,而不能使用UI 事件,因为UI 事件不允许向event对象中再添加新属性(Safari 除外)。像这样模拟事件虽然会触发键盘事件,但却不会向文本框中写入文本,这是由于无法精确模拟键盘事件所造成的。

3. 模拟其他事件

虽然鼠标事件和键盘事件是在浏览器中最经常模拟的事件,但有时候同样需要模拟变动事件和HTML 事件。要模拟变动事件, 可以使用createEvent("MutationEvents") 创建一个包含initMutationEvent() 方法的变动事件对象。这个方法接受的参数包括: type 、bubbles 、cancelable、relatedNode、preValue、newValue、attrName 和attrChange。下面来看一个模拟变动事件的例子。

  1. var event = document.createEvent("MutationEvents");
  2. event.initMutationEvent("DOMNodeInserted", true, false, someNode, "","","",0);
  3. targ et.dispatchEvent(event);

以上代码模拟了DOMNodeInserted 事件。其他变动事件也都可以照这个样子来模拟,只要改一改参数就可以了。
要模拟HTML 事件,同样需要先创建一个event 对象——通过createEvent("HTMLEvents"),然后再使用这个对象的initEvent()方法来初始化它即可,如下面的例子所示。

  1. var event = document.createEvent("HTMLEvents");
  2. event.initEvent("focus", true, false);
  3. targ et.dispatchEvent(event);

这个例子展示了如何在给定目标上模拟focus 事件。模拟其他HTML 事件的方法也是这样。

浏览器中很少使用变动事件和HTML 事件,因为使用它们会受到一些限制。

4. 自定义DOM 事件

DOM3 级还定义了“自定义事件”。自定义事件不是由DOM 原生触发的,它的目的是让开发人员创建自己的事件。要创建新的自定义事件,可以调用createEvent("CustomEvent")。返回的对象有一个名为initCustomEvent()的方法,接收如下4 个参数。

  • type(字符串):触发的事件类型,例如"keydown"。
  • bubbles(布尔值):表示事件是否应该冒泡。
  • cancelable(布尔值):表示事件是否可以取消。
  • detail(对象):任意值,保存在event 对象的detail 属性中。

可以像分派其他事件一样在DOM 中分派创建的自定义事件对象。例如:

  1. var div = document.getElementById("myDiv"),
  2. event;
  3. EventUtil.addHandler(div, "myevent",
  4. function(event) {
  5. alert("DIV: " + event.detail);
  6. });
  7. EventUtil.addHandler(document, "myevent",
  8. function(event) {
  9. alert("DOCUMENT: " + event.detail);
  10. });
  11. if (document.implementation.hasFeature("CustomEvents", "3.0")) {
  12. event = document.createEvent("CustomEvent");
  13. event.initCustomEvent("myevent", true, false, "Hello world!");
  14. div.dispatchEvent(event);
  15. }

运行一下
这个例子创建了一个冒泡事件"myevent"。而event.detail 的值被设置成了一个简单的字符串,然后在<div>元素和document 上侦听这个事件。因为initCustomEvent()方法已经指定这个事件应该冒泡,所以浏览器会负责将事件向上冒泡到document。
支持自定义DOM事件的浏览器有IE9+和Firefox 6+。

13.6.2 IE中的事件模拟

在IE8 及之前版本中模拟事件与在DOM中模拟事件的思路相似:先创建event 对象,然后为其指定相应的信息,然后再使用该对象来触发事件。当然,IE 在实现每个步骤时都采用了不一样的方式。
调用document.createEventObject()方法可以在IE 中创建event 对象。但与DOM方式不同的是,这个方法不接受参数,结果会返回一个通用的event 对象。然后,你必须手工为这个对象添加所有必要的信息(没有方法来辅助完成这一步骤)。最后一步就是在目标上调用fireEvent()方法,这个方法接受两个参数:事件处理程序的名称和event 对象。在调用fireEvent()方法时,会自动为event 对象添加srcElement 和type 属性;其他属性则都是必须通过手工添加的。换句话说,模拟任何IE 支持的事件都采用相同的模式。例如,下面的代码模拟了在一个按钮上触发click 事件过程。

  1. var btn = document.getElementById("myBtn");
  2. //创建事件对象
  3. var event = document.createEventObject();
  4. //初始化事件对象
  5. event.screenX = 100;
  6. event.screenY = 0;
  7. event.clientX = 0;
  8. event.clientY = 0;
  9. event.ctrlKey = false;
  10. event.altKey = false;
  11. event.shiftKey = false;
  12. event.button = 0;
  13. //触发事件
  14. btn.fireEvent("onclick", event);

运行一下
这个例子先创建了一个event 对象,然后又用一些信息对其进行了初始化。注意,这里可以为对象随意添加属性,不会有任何限制——即使添加的属性IE8 及更早版本并不支持也无所谓。在此添加的属性对事件没有什么影响,因为只有事件处理程序才会用到它们。
采用相同的模式也可以模拟触发keypress 事件,如下面的例子所示。

  1. var textbox = document.getElementById("myTextbox");
  2. //创建事件对象
  3. var event = document.createEventObject();
  4. //初始化事件对象
  5. event.altKey = false;
  6. event.ctrlKey = false;
  7. event.shiftKey = false;
  8. event.keyCode = 65;
  9. //触发事件
  10. textbox.fireEvent("onkeypress", event);

运行一下
由于鼠标事件、键盘事件以及其他事件的event 对象并没有什么不同,所以可以使用通用对象来触发任何类型的事件。不过,正如在DOM中模拟键盘事件一样,运行这个例子也不会因模拟了keypress而在文本框中看到任何字符,即使触发了事件处理程序也没有用。

下载离线版教程:http://www.shouce.ren/api/view/a/15218

13.6 模拟事件【JavaScript高级程序设计第三版】的更多相关文章

  1. JavaScript高级程序设计第三版.CHM【带实例】

    从驱动全球商业.贸易及管理领域不计其数的复杂应用程序的角度来看,说 JavaScript 已经成为当今世界上最流行的编程语言一点儿都不为过. JavaScript 是一种非常松散的面向对象语言,也是 ...

  2. 模拟事件【JavaScript高级程序设计第三版】

    事件,就是网页中某个特别值得关注的瞬间.事件经常由用户操作或通过其他浏览器功能来触发.但很少有人知道,也可以使用JavaScript 在任意时刻来触发特定的事件,而此时的事件就如同浏览器创建的事件一样 ...

  3. javascript高级程序设计第三版书摘

    在HTML 中使用JavaScript <script>元素 在使用<script>元素嵌入 JavaScript 代码时,只须为<script>指定 type 属 ...

  4. 13.4.3 鼠标与滚轮事件【JavaScript高级程序设计第三版】

    鼠标事件是Web 开发中最常用的一类事件,毕竟鼠标还是最主要的定位设备.DOM3 级事件中定义了9 个鼠标事件,简介如下. click:在用户单击主鼠标按钮(一般是左边的按钮)或者按下回车键时触发.这 ...

  5. JavaScript高级程序设计第三版-读书笔记(1-3章)

    这是我第一次用markdown,也是我第一次在网上记录我自己的学习过程. 第一章 JavaScript主要由以下三个不同的部分构成 ECMAScript   提供核心语言功能 DOM     提供访问 ...

  6. DOM 操作技术【JavaScript高级程序设计第三版】

    很多时候,DOM 操作都比较简明,因此用JavaScript 生成那些通常原本是用HTML 代码生成的内容并不麻烦.不过,也有一些时候,操作DOM 并不像表面上看起来那么简单.由于浏览器中充斥着隐藏的 ...

  7. 10.1.2 Document类型【JavaScript高级程序设计第三版】

    JavaScript 通过Document 类型表示文档.在浏览器中,document 对象是HTMLDocument(继承自Document 类型)的一个实例,表示整个HTML 页面.而且,docu ...

  8. 10.2 DOM 操作技术【JavaScript高级程序设计第三版】

    很多时候,DOM 操作都比较简明,因此用JavaScript 生成那些通常原本是用HTML 代码生成的内容并不麻烦.不过,也有一些时候,操作DOM 并不像表面上看起来那么简单.由于浏览器中充斥着隐藏的 ...

  9. 2.1 <script>元素【JavaScript高级程序设计第三版】

    向 HTML 页面中插入 JavaScript 的主要方法,就是使用<script>元素.这个元素由 Netscape 创造并在 Netscape Navigator 2 中首先实现.后来 ...

随机推荐

  1. MarkDown和流程图诠释你的代码

    写在前面:首先感谢导师-猴哥对我的认可(求多分享点编程经验.工具.多开课),学习编程是一个痛苦和快乐的过程,希望大家共勉 本文介绍MarkDown的基本语法.使用MarkDown画简单的流程图.使用X ...

  2. shell中和RDA中的alert日志中文乱码

    客户端字符集无法识别中文,只能下载到本机使用nodepad++查看

  3. 获取v$latch数据源实验

    实验环境:Oracle Rac 11.2.0.3 首先获取v$latch的定义:通过PL/SQL或者get ddl等常规途径只能获取到v_$latch相关的视图信息.需要通过特殊方法获取v$latch ...

  4. RAC修改spfile位置

    RAC修改spfile位置    [root@rac1 ~]# su - oracle  [oracle@rac1 ~]$ sqlplus  / as sysdba  SQL*Plus: Releas ...

  5. 解决Myeclipse报PermGen space异常的问题

    最近使用eclipse做开发,使用的服务器是tomcat,但在启动时报了Caused by: java.lang.OutOfMemoryError: PermGen space的异常. 这个错误很常见 ...

  6. 如何将BSP应用配置成Fiori Launchpad上的一个tile

    当我们通过WebIDE或者Eclipse的插件Team Provider把一个本地开发好的UI5应用部署到了ABAP Netweaver服务器上之后,我们可以将该UI5应用配置成Fiori launc ...

  7. IOS 蓝牙(GameKit、Core Bluetooth)

    GameKit的蓝牙开发注意 ● 只能用于iOS设备之间的连接 ● 只能用于同一个应用程序之间的连接 ● 最好别利用蓝牙发送比较大的数据 /* 关于蓝牙的数据传输  1. 一次性传送,没有中间方法,所 ...

  8. c++利用互斥锁实现读写锁

    很简单就是在读的时候把写的锁锁住就好了 class readwrite_lock { public: readwrite_lock() : read_cnt(0) { } void readLock( ...

  9. 前端开发css禁止选中文本

    在我们日常的Java web前端开发的过程中呢,程序员们会遇到各种各样的要求,所以不每天学的东西感觉自己都退步了,都更不上时代的发展了. 每天应对各种需求,每天活在疑问中就是我们程序员的真是写照.但我 ...

  10. hdu1215 七夕节---因子和

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1215 题目大意: 求N的因子和(不包括N本身) 解题思路: 模板传送门 #include<io ...