前面的话

  事件是网页中某个特别的瞬间,经常由用户操作或通过其他浏览器功能来触发。但实际上,也可以使用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. 经典排序算法 – 插入排序Insertion sort

    经典排序算法 – 插入排序Insertion sort  插入排序就是每一步都将一个待排数据按其大小插入到已经排序的数据中的适当位置,直到全部插入完毕. 插入排序方法分直接插入排序和折半插入排序两种, ...

  2. ajax内调用WCF服务

    WCF可以当作WebService一样被调用,在html内通过ajax调用WCF服务的方法如下: 1.新建一个WCF服务的网站项目: 2.在项目内增加一个新项:启用了ajax的WCF服务: 3.在对应 ...

  3. codeforces 360 E - The Values You Can Make

    E - The Values You Can Make Description Pari wants to buy an expensive chocolate from Arya. She has  ...

  4. 【Beta】Daily Scrum Meeting第一次

    1.任务进度 学号 已完成 接下去要做 502 更换网络框架为okHttp 搭建好PHP单元测试环境,写出PHP测试的demo 509 PHP的login返回值:插入数据改为单行插入:系负责人更新单行 ...

  5. swfupload纠结bug总结

    上传控件传到客户端的信息在IE7下乱码: 服务端 HttpUtility.UrlEncode,客户端 decodeURIComponent 上传大文件报404错: 用fiddler截取发现提示: 最可 ...

  6. 关于mySQL自连接的一些用法

    自连接是连接的一种用法,但并不是连接的一种类型,因为他的本质是把一张表当成两张表来使用. 举例说明: 这是一张职员信息表,如果我要查询这张表中的每个职员的上司,那么必须使用自连接来查询.所以为了能实现 ...

  7. Swift 3 and OpenGL on Linux and macOS with GLFW

    https://solarianprogrammer.com/2016/11/19/swift-opengl-linux-macos-glfw/ Swift 3 and OpenGL on Linux ...

  8. StartSSL免费SSL证书申请和账户注册完整过程

    StartSSL算是比较早提供免费SSL证书的第三方提供商,我们可以免费申请且免费续期使用到有需要HTTPS网址的用户.关于网站使用SSL证书主要还是因为谷歌在向导说明中提到如果一个网站使用到SSL证 ...

  9. 通过反射获取DLL的类实现加载窗体

    1.创建一个DLL 类库,并新建一个窗体类,这个直接在vs上操作就好 2. 建立一个Testassembly工程 新建一个测试类 namespace Testassembly { public par ...

  10. 利用Generator解决异步回调原理

    var i = 0; i++; function ajax(url){ return new Promise(function(resolve, reject){ setTimeout(functio ...