前面的话

  事件是网页中某个特别的瞬间,经常由用户操作或通过其他浏览器功能来触发。但实际上,也可以使用javascript在任意时刻来触发特定的事件,而此时的事件就如同浏览器创建的事件一样。本文将详细介绍事件模拟

引入

  以下面的实际需求为例,来详细说明事件模拟的使用。按钮一的点击效果是弹出1。而我们通过新增按钮二来模拟按钮一的效果

<button id="btn1">按钮一</button>
<script>
btn1.onclick = function(){
alert(1);
}
</script>

事件复制

  通过调用相同的事件处理函数,来完成相同的功能

<button id="btn1">按钮一</button>
<button id="btn2">按钮二</button>
<script>
btn1.onclick=function(){
alert(1);
}
btn2.onclick = btn1.onclick;
</script>

  但是,有一个问题,在不知道按钮一的事件处理函数以及以何种调用形式调用时,这种方法是危险的

  下面这种情况将无法正确模拟

<button id="btn1">按钮一</button>
<button id="btn2">按钮二</button>
<script>
if(btn1.addEventListener){
btn1.addEventListener('click',function(){alert(1);})
}else{
btn1.attachEvent('onclick',function(){alert(1);})
}
btn2.onclick = btn1.onclick;
</script>

click()方法

  使用click()方法,则无论使用何种事件处理程序都可以实现模拟效果

<button id="btn1">按钮一</button>
<button id="btn2">按钮二</button>
<script>
if(btn1.addEventListener){
btn1.addEventListener('click',function(){alert(1);})
}else{
btn1.attachEvent('onclick',function(){alert(1);})
}
btn2.onclick = function(){
btn1.click();
}
</script>

  虽然click()方法可以完美模拟click事件,但是对于其他事件并没有相应的模拟方法,就需要用到下面要介绍的事件模拟了。好吧,我承认这个引入比较长。但是,我不知道如何再缩短了

模拟机制

  事件模拟包括3个部分:创建事件、初始化以及触发事件。某些情况下,初始化与创建事件一起进行。最终,通过dispatchEvent()方法或fireEvent()方法来触发事件

  对于不同的事件类型,有不同的创建方法。下面以mouseover事件为例

MouseEvent()

  使用MouseEvent()方法可以创建鼠标事件。实际上,MouseEvent()方法在创建事件的同时,也包括了初始化的操作

  [注意]IE浏览器和safari浏览器不支持

  最后使用dispatchEvent()方法在当前节点上触发指定事件。该方法返回一个布尔值,只要有一个监听函数调用了Event.preventDefault(),则返回值为false,否则为true

  [注意]IE8-浏览器不支持

function simulateMouseOver(obj) {
var event = new MouseEvent('mouseover', {
'bubbles': true,
'cancelable': true
});
obj.dispatchEvent(event);
}
<button id="btn1">按钮一</button>
<button id="btn2">按钮二</button>
<script>
if(btn1.addEventListener){
btn1.addEventListener('mouseover',function(){alert(1);})
}else{
btn1.attachEvent('onmouseover',function(){alert(1);})
}
function simulateMouseOver(obj) {
var event = new MouseEvent('mouseover', {
'bubbles': true,
'cancelable': true
});
obj.dispatchEvent(event);
}
btn2.onmouseover = function(){
simulateMouseOver(btn1);
}
</script>

creatEvent()

  在document对象上使用createEvent()方法可以用来创建event对象。这个方法接收一个参数,表示要创建的事件类型的字符串

  [注意]IE8-浏览器不支持createEvent()方法

  在使用document.createElement创建事件之后,还需要使用与事件有关的信息对其进行初始化,每种不同类型的事件都有不同的初始化方法

事件类型                事件初始化方法
UIEvents event.initUIEvent
MouseEvents event.initMouseEvent
MutationEvents event.initMutationEvent
HTMLEvents event.initEvent
Event event.initEvent
CustomEvent event.initCustomEvent
KeyboardEvent event.initKeyEvent

  下面是initMouseEvent()方法的参数,它们与鼠标事件的event对象所包含的属性一一对应。其中,前4个参数对正确地激发事件至关重要,因为浏览器要用到这些参数;而剩下的所有参数只有在事件处理程序中才会用到

  [注意]IE8-浏览器不支持initMouseEvent()方法

  type(字符串):表示要触发的事件类型,例如"click"

  bubbles(布尔值):表示事件是否应该冒泡。为精确地模拟鼠标事件,应该把这个参数设置为true

  cancelable(布尔值):表示事件是否可以取消。为精确地模拟鼠标事件,应该把这个参数设置为crue

  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时使用

【写法一】createEvent()方法使用MouseEvents参数

function simulateMouseOver(obj) {
var event = document.createEvent('MouseEvents');
event.initMouseEvent('mouseover',true,true,document.defaultView,0,0,0,0,0,false,false,false,false,0,null);
obj.dispatchEvent(event);
}
<button id="btn1">按钮一</button>
<button id="btn2">按钮二</button>
<script>
if(btn1.addEventListener){
btn1.addEventListener('mouseover',function(){alert(1);})
}else{
btn1.attachEvent('onmouseover',function(){alert(1);})
}
function simulateMouseOver(obj) {
var event = document.createEvent('MouseEvents');
event.initMouseEvent('mouseover',true,true,document.defaultView,0,0,0,0,0,false,false,false,false,0,null);
obj.dispatchEvent(event);
}
btn2.onmouseover = function(){
simulateMouseOver(btn1);
}
</script>

【写法二】createEvent()方法使用Event参数

function simulateMouseOver(obj) {
var event = document.createEvent('Event');
event.initEvent('mouseover',true,true,document.defaultView,0,0,0,0,0,false,false,false,false,0,null);
obj.dispatchEvent(event);
}
<button id="btn1">按钮一</button>
<button id="btn2">按钮二</button>
<script>
if(btn1.addEventListener){
btn1.addEventListener('mouseover',function(){alert(1);})
}else{
btn1.attachEvent('onmouseover',function(){alert(1);})
}
function simulateMouseOver(obj) {
var event = document.createEvent('Event');
event.initEvent('mouseover',true,true,document.defaultView,0,0,0,0,0,false,false,false,false,0,null);
obj.dispatchEvent(event);
}
btn2.onmouseover = function(){
simulateMouseOver(btn1);
}
</script>

createEventObject()

  在IE10-浏览器中可以使用document.createEventObject()方法创建event对象。这个方法不接受参数,结果会返回一个通用的event对象

  IE浏览器不支持初始化事件,需要手动为这个对象添加所有必要的信息

  IE8-浏览器不支持dispatchEvent()事件。在IE8-浏览器中触发事件需要调用fireEvent()方法,这个方法接受两个参数:事件处理程序的名称和event对象。在调用fireEvent()方法时,会自动为event对象添加srcElement和type属性

function simulateMouseOver(obj) {
var event = document.createEventObject();
event.bubbles = true;
event.cancelable = true;
obj.fireEvent('onmouseover',event);
}

兼容

  下面使用document.createEvent()方法和createEventObject()来实现兼容 

function simulateMouseOver(obj) {
var event;
if(document.createEvent){
event = document.createEvent('Event');
event.initEvent('mouseover',true,true,document.defaultView,0,0,0,0,0,false,false,false,false,0,null);
obj.dispatchEvent(event);
}else{
event = document.createEventObject();
event.bubbles = true;
event.cancelable = true;
obj.fireEvent('onmouseover',event);
}
}
<button id="btn1">按钮一</button>
<button id="btn2">按钮二</button>
<script>
if(btn1.addEventListener){
btn1.addEventListener('mouseover',function(){alert(1);})
}else{
btn1.attachEvent('onmouseover',function(){alert(1);})
}
function simulateMouseOver(obj) {
var event;
if(document.createEvent){
event = document.createEvent('Event');
event.initEvent('mouseover',true,true,document.defaultView,0,0,0,0,0,false,false,false,false,0,null);
obj.dispatchEvent(event);
}else{
event = document.createEventObject();
event.bubbles = true;
event.cancelable = true;
obj.fireEvent('mouseover',event);
}
}
btn2.onmouseover = function(){
simulateMouseOver(btn1);
}
</script>

自定义事件

  自定义事件不是由DOM原生触发的,它的目的是让开发人员创建自己的事件

Event()

  最简单的就是使用Event()构造函数

  [注意]IE和safari浏览器不支持

<button id="btn">按钮</button>
<script>
function customEvent(obj){
var event = new Event('changeColor');
obj.addEventListener('changeColor',function(){
this.style.backgroundColor = 'lightblue';
})
return event;
}
btn.onclick = function(){
this.dispatchEvent(customEvent(this));
}
</script>

CustomEvent()

  如果需要在触发事件的同时,传入指定的数据,需要使用CustomEvent构造函数生成自定义的事件对象 

<button id="btn">按钮</button>
<script>
function customEvent(obj){
var event = new CustomEvent('changeColor', { 'detail': 'hello' });
obj.addEventListener('changeColor',function(e){
e = e || event;
this.style.backgroundColor = 'lightblue';
this.innerHTML = e.detail;
})
return event;
}
btn.onclick = function(){
this.dispatchEvent(customEvent(this));
}
</script>

createEvent()

  要创建新的自定义事件,可以调用createEvent("CustomEvent")。返回的对象有一个名为initCustomEvent()的方法,接收如下4个参数

  type(字符串):触发的事件类型,例如"keydown"

  bubbles(布尔值):表示事件是否应该冒泡

  cancelable(布尔值):表示事件是否可以取消

  detail(对象):任意值,保存在event对象的detail属性中

  [注意]IE8-浏览器不支持

<button id="btn">按钮</button>
<script>
function customEvent(obj){
var event = document.createEvent('CustomEvent');
event.initCustomEvent('changeColor',true,true,'hello');
obj.addEventListener('changeColor',function(e){
e = e || event;
this.style.backgroundColor = 'lightblue';
this.innerHTML = e.detail;
})
return event;
}
btn.onclick = function(){
this.dispatchEvent(customEvent(this));
}
</script>

最后

  事件模拟是用来触发自定义的事件函数的,而不是来触发浏览器默认行为的

  所以,试图通过事件模拟的形式来触发浏览器默认行为是不可行的。比如点击鼠标右键实现键盘backspace键的删除效果是不可行的

深入理解DOM事件机制系列第四篇——事件模拟的更多相关文章

  1. 深入理解DOM事件机制系列第三篇——事件对象

    × 目录 [1]获取 [2]事件类型 [3]事件目标[4]事件代理[5]事件冒泡[6]事件流[7]默认行为 前面的话 在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含着所有与事 ...

  2. 深入理解DOM事件类型系列第四篇——剪贴板事件

    × 目录 [1]定义 [2]对象方法 [3]应用 前面的话 剪贴板操作可能看起来不起眼,但是却十分有用,可以增强用户体验,方便用户操作.本文将详细介绍剪贴板事件 定义 剪贴板操作包括剪切(cut).复 ...

  3. 深入理解javascript函数进阶系列第四篇——惰性函数

    前面的话 惰性函数表示函数执行的分支只会在函数第一次调用的时候执行,在第一次调用过程中,该函数会被覆盖为另一个按照合适方式执行的函数,这样任何对原函数的调用就不用再经过执行的分支了.本文将详细介绍惰性 ...

  4. 深入理解脚本化CSS系列第四篇——脚本化样式表

    × 目录 [1]CSSStyleSheet [2]CSSRule 前面的话 关于脚本化CSS,查询样式时,查询的是计算样式:设置单个样式时,设置的是行间样式:设置多个样式时,设置的是CSS类名.脚本化 ...

  5. 深入理解javascript作用域系列第四篇——块作用域

    × 目录 [1]let [2]const [3]try 前面的话 尽管函数作用域是最常见的作用域单元,也是现行大多数javascript最普遍的设计方法,但其他类型的作用域单元也是存在的,并且通过使用 ...

  6. 深入理解javascript作用域系列第四篇

    前面的话 尽管函数作用域是最常见的作用域单元,也是现行大多数javascript最普遍的设计方法,但其他类型的作用域单元也是存在的,并且通过使用其他类型的作用域单元甚至可以实现维护起来更加优秀.简洁的 ...

  7. 前端工程师技能之photoshop巧用系列第四篇——图片格式

    × 目录 [1]图片格式 [2]保存设置 前面的话 对于前端来说,图片格式是需要重要掌握的知识.本文是photoshop巧用系列第四篇——图片格式 图片格式 目前在前端的开发中常用的图片格式有jpg. ...

  8. 深入理解DOM事件机制系列第二篇——事件处理程序

    × 目录 [1]HTML [2]DOM0级 [3]DOM2级[4]IE[5]总结 前面的话 事件处理程序又叫事件侦听器,实际上就是事件的绑定函数.事件发生时会执行函数中相应代码.事件处理程序有HTML ...

  9. 深入理解DOM事件机制系列第一篇——事件流

    × 目录 [1]历史 [2]事件冒泡 [3]事件捕获[4]事件流 前面的话 javascript操作CSS称为脚本化CSS,而javascript与HTML的交互是通过事件实现的.事件就是文档或浏览器 ...

随机推荐

  1. MD5加密的Java实现

    在各种应用系统中,如果需要设置账户,那么就会涉及到储存用户账户信息的问题,为了保证所储存账户信息的安全,通常会采用MD5加密的方式来,进行储存.首先,简单得介绍一下,什么是MD5加密. MD5的全称是 ...

  2. 一些ES5的操作数组的方法

    在ES5规范中新增了不少操作数组的方法,特此罗列一下以备使用 1. forEach循环 有点类似jQuery的each循环 [12,23,36,4,5].forEach(function(v,k){ ...

  3. smack 4.1创建群聊

    smack 4.1.1版本对群聊修改了很多,MultUserChat的构造函数修改成了私有,以前通过new MultUserChat创建聊天室,现在通过MultUserChatMananger先通过r ...

  4. JS 将数字转化成为货币格式

    最近由于项目的需要需要将数字format成货币格式,自己搞了半天效果不是很好,博客园有篇问题很好,再次转载记录一下 http://www.cnblogs.com/mingmingruyuedlut/a ...

  5. vs2012 打开解决方案崩溃或者点击项目崩溃

    报错: 问题签名:  问题事件名称: CLR20r3 解决方案: 步骤1:开始-->所有程序-->Microsoft Visual Studio 2012-->Visual Stud ...

  6. java发送邮件..转

    使用Java应用程序发送E-mail十分简单,但是首先你应该在你的机器上安装JavaMail API 和Java Activation Framework (JAF) . 你可以在 JavaMail ...

  7. Smart3D系列教程6之 《案例实战演练3——倾斜数据正射影像及DSM的生产》

    一.前言 Wish3D出品的系列教程中,前面两讲分别讲述说明了小物件的照片三维重建.大区域地形的三维重建,从照片的直接导入至软件到通过Excel表格将区块导入处理,从不同的模型类别.不同的导入方式演示 ...

  8. Task异步编程

    Task异步编程中,可以实现在等待耗时任务的同时,执行不依赖于该耗时任务结果的其他同步任务,提高效率. 1.Task异步编程方法签名及返回值: a) 签名有async 修饰符 b) 方法名以 Asyn ...

  9. oracle--导出、导入blob类型的字段

    blob是oracle中的一个数据类型,保存的是压缩后的二进制形式的大数据. 数据迁移如果涉及到blob字段,都不好处理,因为无法用常规方法进行操作,如:使用select查看该字段,也无法用inser ...

  10. java学习之面向对象(3)

    下面来谈谈java编程中的一些语法: 1.什么是对象数组? 对象数组就是数组里的每个元素都是类的对象,赋值时先定义对象,然后将对象直接赋值给数组. 对象数组的声明: 类名[]  对象数组名称  = n ...