事件,就是网页中某个特别值得关注的瞬间。事件经常由用户操作或通过其他浏览器功能来触发。
但很少有人知道,也可以使用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
2
3
4
5
6
7
8
var btn = document.getElementById("myBtn");
//创建事件对象
var event = document.createEvent("MouseEvents");
//初始化事件对象
event.initMouseEvent("click"truetrue, document.defaultView, 0, 0, 0, 0, 0,
falsefalsefalsefalse, 0, null);
//触发事件
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
2
3
4
5
6
7
8
9
10
var textbox = document.getElementById("myTextbox"),
event;
//以DOM3 级方式创建事件对象
if (document.implementation.hasFeature("KeyboardEvents""3.0")) {
    event = document.createEvent("KeyboardEvent");
    //初始化事件对象
    event.initKeyboardEvent("keydown"truetrue, document.defaultView, "a", 0, "Shift", 0);
}
//触发事件
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
2
3
4
5
6
7
8
9
//只适用于Firefox
var textbox = document.getElementById("myTextbox")
//创建事件对象
var event = document.createEvent("KeyEvents");
//初始化事件对象
event.initKeyEvent("keypress"truetrue, document.defaultView, falsefalse,
falsefalse, 65, 65);
//触发事件
textbox.dispatchEvent(event);

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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);

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

3. 模拟其他事件

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

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

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

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

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

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

4. 自定义DOM 事件

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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"truefalse"Hello world!");
    div.dispatchEvent(event);
}

运行一下
这个例子创建了一个冒泡事件"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
2
3
4
5
6
7
8
9
10
11
12
13
14
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);

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

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

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

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

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

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

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

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

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

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

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

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

  5. 22.1 高级函数【JavaScript高级程序设计第三版】

    函数是JavaScript 中最有趣的部分之一.它们本质上是十分简单和过程化的,但也可以是非常复杂和动态的.一些额外的功能可以通过使用闭包来实现.此外,由于所有的函数都是对象,所以使用函数指针非常简单 ...

  6. 21.1 XMLHttpRequest 对象【JavaScript高级程序设计第三版】

    IE5 是第一款引入XHR 对象的浏览器.在IE5 中,XHR 对象是通过MSXML 库中的一个ActiveX对象实现的.因此,在IE 中可能会遇到三种不同版本的XHR 对象,即MSXML2.XMLH ...

  7. 14.5 富文本编辑【JavaScript高级程序设计第三版】

    富文本编辑,又称为WYSIWYG(What You See Is What You Get,所见即所得).在网页中编辑富文本内容,是人们对Web 应用程序最大的期待之一.虽然也没有规范,但在IE 最早 ...

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

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

  9. 23.3.3 Web存储机制【JavaScript高级程序设计第三版】

    Web Storage 最早是在Web 超文本应用技术工作组(WHAT-WG)的Web 应用1.0 规范中描述的. 这个规范的最初的工作最终成为了HTML5 的一部分.Web Storage 的目的是 ...

随机推荐

  1. Python2.7-netrc

    netrc 模块,用于解析和封装 netrc 类型的文件,这种类型的文件用于 unix 的 ftp 程序和其他 ftp 客户端.----------------不知道到底是个什么东西 1.模块对象 1 ...

  2. easyui combotree combobox 使用例子

    <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> &l ...

  3. Vim2.1-Vim简明教程【CoolShell】【非原创】

    vim的学习曲线相当的大(参看各种文本编辑器的学习曲线),所以,如果你一开始看到的是一大堆VIM的命令分类,你一定会对这个编辑器失去兴趣的.下面的文章翻译自<Learn Vim Progress ...

  4. MFC Edit控件的使用~~

    EditBox,一般用于显示数字文本,或者与用户沟通获取数字文本. 这里介绍一种将EditBox与一个变量关联起来的方法: 快捷键:Shift + Ctrl + X,进入类导向,选择成员变量属性页: ...

  5. 【中间件】Redis 实战之主从复制、高可用、分布式

    目录 简介 持久化 主从复制 高可用 Redis-Sentinel .NET Core开发 分布式 Redis-Cluster 配置说明 常见问题 简介 本节内容基于 CentOS 7.4.1708, ...

  6. numpy 初识(三)

    基本运算 exp: e sqrt:开放 floor:向下取整 ravel:矩阵拉成一个向 T:转置(行和列变换) 改变形状: resize: 更改其形状(返回值为None)a.resize(6,2) ...

  7. 绕WAF&安全狗新姿势

    俗话说只要思路宽,绕狗绕的欢.前段时间我有尝试着用以下的方法绕狗,效果还不错.不过这方法呢也许这段时间可以绕过,过段时间可能就失效了,大家还是要多去尝试找到更多的方法. 举例-->整型注入 绕过 ...

  8. unity2D限制位置的背景移动补偿效果

    有时候我们想要背景可以跟随相机移动补偿,但是又不想该背景物体离原来的位置太远,比如我们想要一棵树在一个房子的后面,然后使用相机补偿使其跟随移动,达到3D错觉效果,但是我们又不想该物体偏离房屋太远.假设 ...

  9. 172. Remove Element【LintCode by java】

    Description Given an array and a value, remove all occurrences of that value in place and return the ...

  10. 原生js实现table的排序

    原生js实现table的排序 今天遇到了一个问题就是使用原生js对table标签进行排序 一开始的时候陷入了一个误区就是首先获取table,然后每次比较完大小都会交换children的值,准备到最后吧 ...