1.事件流

1.1.标准事件流

所谓的标准事件流指的的:EMCAScript标准规定事件流包含三个阶段,分别为事件捕获阶段,处于目标阶段,事件冒泡阶段。

下面是一段html代码,根据代码来说明标准事件流。

<!DOCTYPE HTML>
<html>
<body>
<div>
<button>click</button>
</div>
</body>
</html>

在上面的代码中,如果点击按钮button,则标准事件触发分别经历以下三个阶段:

事件触发一次经历三个阶段,所以我们在一个元素上注册事件也就可以在对应阶段注册事件,移除事件也同样。

target.addEventListener(type, listener, useCapture);   //标准注册事件函数
                                //target:target: 文档节点、document、window 或 XMLHttpRequest。
                                //函数的参数,分别为 注册事件类型---type不包含on,事件的回调函数,事件注册在捕获期间还是冒泡期间
                                //例如:给button注册onclick事件,要是在捕获阶段注册,则 button.addEventListener("click",function(){},true);
target.removeEventListener(type, listener, useCapture);  //在某一个元素上撤销已注册的事件。 这里强调的是 这里的函数必须与已注册的函数是同一个函数!

1.2.IE中事件流

虽然大部分的浏览器都遵循着标准,但是在IE浏览器中,事件流却是非标准的。IE中事件流只有两个阶段: 处于目标阶段,冒泡阶段。

上面的HTML结构,如果是在IE中,事件流执行时如图所示:

对应着在IE中的事件注册和撤销事件函数:

target.attachEvent(type, listener);  //target: 文档节点、document、window 或 XMLHttpRequest。
//函数参数: type----包含on.type一般为“onclick”,"onkeydown"
// listener:事件触发时的回调函数。
target.detachEvent(type,listener);   //参数与注册参数相对应。

因为,IE中事件流没有捕获阶段,所以相应的在注册事件和撤销事件时比标准注册事件少一个参数。

1.3.事件的执行顺序

  为什么要单独提出事件的执行顺序? 是因为一些事件有其默认的行为,比如在文本框中按下鼠标左键,文本框文本框获得焦点;点击一个超链接,超链接进行跳转。 那么,事件的执行顺序是怎样的呢?

一般事件的执行顺序: 事件的捕获阶段====>处于目标阶段====>事件的冒泡阶段====>事件的默认行为。

正因为事件的默认行为是最后执行的,我们才得以机会阻止事件的默认行为。

如下,阻止文本框获取焦点:

//阻止文本框获取焦点  
var input=document.getElementById("inputText");
input.onmousedown=function(event){
event=event||window.event;
if(event.preventDefault){ //非IE浏览器阻止事件默认行为
event.preventDefault();
}else{
event.returnValue=false;//IE浏览器阻止事件默认行为
}
}

1.4.跨浏览器注册事件

因为IE中浏览器注册事件比较特殊,下面是一个跨浏览器注册函数。

var EventUtil =  {
addEventListener: function (element, type, callback) { //注册事件,因为浏览器的兼容性考虑,注册事件一般都是注册在事件的冒泡阶段
if (element.addEventListener) {
element.addEventListener(type, callback, false);
} else if (element.attachEvent) {
element.attachEvent('on' + type, callback);
} else {
element['on' + type] = callback;
}
},
removeEventListener: function(element, type, callback) { //撤销事件
if (element.removeEventListener) {
element.removeEventListener(type, callback, false);
} else if (element.detachEvent) {
element.detachEvent('on' + type, callback);
} else {
element['on' + type] = null;
}
}
};

2.DOM事件

2.1DOM0级事件

通过javaScript指定事件处理程序的传统方式,就是将一个函数赋值给一个事件处理程序的属性。这种为事件处理程序赋值的方法是在第四代Web浏览器中出现的,而且至今仍然为所有现在浏览器支持。原因主要有两点: 1.简单 2.具有跨浏览器优势。

每个元素(window和document)都有自己的事件处理程序属性,这些属性通常全部小写,例如 onclick, onmousedown.

var btn = document.getElementById('mybtn');
btn.onclick = function () {
alert('click');
}

DOM0级事件有其自身的局限性,

1.那就是某一个属性只能赋值给一个函数,也就导致在某一个元素上的某一个事件属性只能对应着一个函数。多次注册时,已最     后一次注册为准。

2.DOM0级事件全部都是默认在冒泡阶段执行。

2.2.DOM2级事件

我们在第一部分所定义的跨浏览注册事件函数,就是一个DOM2级注册事件。DOM2级注册事件相比于DOM0级的优势就在于其可以多次注册,并且执行顺序与注册顺序一致。

var btn = document.getElementById('mybtn');

function fun1(){ alert("1");}
function fun2(){ alert("2");}
EventUtil.addEventListener(btn,"click",fun1);  //注册事件
EventUtil.addEventListener(btn,"click",fun1); //触发事件的时候会 先弹出 1 在弹出 2

如果不考虑IE浏览器,我们还可以在事件的捕获阶段,注册事件,但是一般因兼容性考虑,我们很少在事件的捕获阶段注册事件。

3.事件对象

在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含着所有事件有关的信息。

例如,单击事件中会包含鼠标的位置信息,键盘触发的事件中会包含按下的键位有关的信息。

所有的浏览器都支持event,但支持的方式却有不同。

3.1.标准浏览器中的事件对象

属性                   类型               读写  描述
bubbles boolean 只读 返回布尔值,指示事件是否是起泡冒泡
cancelable boolean 只读 返回布尔值,指示事件是否可拥可取消的默认动作。
currentTarget Element 只读 返回其事件监听器触发该事件的元素。
eventPhase Intenger 只读 返回事件传播的当前阶段。
target Element 只读 返回触发此事件的元素(事件的目标节点)。
timeStamp Date 只读 返回事件生成的日期和时间。
type String 只读 返回当前 Event 对象表示的事件的名称。
trusted boolean 只读 该事件是否是浏览器生成(true代表是,false代表是开发人员创建
preventDefault Function 只读 取消事件的默认行为在cancelable=true时有效
stopPropagation Function 只读 取消事件的捕获或者冒泡行为在bubbles=true时有效

在事件处理程序内部,对象this始终指向currentTarget的值,而target则只包含事件的实际目标。

3.2.IE中的事件对象

属性                   类型               读写  描述
cancelBubble boolean 读/写 返回布尔值,指示事件是否是起泡冒泡
returnValue boolean 读/写 返回布尔值,指示事件是否可拥可取消的默认动作。
srcElement Element 只读 返回其事件监听器触发该事件的元素。
type String 只读 被触发事件的类型

上面的这些属性,是任何一个事件均会具有的属性。

在IE中有些srcElement对应着target;

执行event.returnValue=false对应着event.preventDefault();

执行event.cancelBubble=true对应着event.stopPropagation();

同时对于一些相关属性IE 比如 relatedTarget属性对应IE中的fromElement和toElement.属性.

3.3.跨浏览器事件对象

因为IE和标准浏览器的不同,所以为了克服这样或者那样的问题,现在编写一个工具包克服兼容性的问题:

 var EventUtil =  {
addEventListener: function (element, type, callback) { //注册事件,因为浏览器的兼容性考虑,注册事件一般都是注册在事件的捕获阶段
if (element.addEventListener) {
element.addEventListener(type, callback, false);
} else if (element.attachEvent) {
element.attachEvent('on' + type, callback);
} else {
element['on' + type] = callback;
}
},
getEvent:function(event){ //获取事件
return event||window.event;
},
getTarget:function(event){ //获取事件的触发目标
return event.target||event.srcElement;
},
preventDefault:function(event){ //阻止事件的默认行为
event.preventDefault?event.preventDefault():event.returnValue=false;
},
stopPropagation:function(event){ //阻止事件冒泡
event.stopPropagation?event.stopPropagation:event.cancelBubble=true;
},
removeEventListener: function(element, type, callback) { //撤销事件
if (element.removeEventListener) {
element.removeEventListener(type, callback, false);
} else if (element.detachEvent) {
element.detachEvent('on' + type, callback);
} else {
element['on' + type] = null;
}
}
};

每个事件在其被触发时,都有一些其特有的属性,比如键盘事件会有键位信息,鼠标事件会有会有位置信息。onmouseenter事件会有fromElement(IE)中,relatedTarget(非IE);onmouseover事件会有toElement(IE)中,relatedTarget(非IE).

详情在W3C教程中有进一步的叙述。W3C事件详解

4.自定义事件

4.1.模拟鼠标事件

非IE浏览器

创建鼠标事件的方法是createEvent()传入字符串“MouseEvent”.返回的对象有initMouseEvent()方法,这个方法有15个参数,分别与鼠标事件中某个典型的属性一一对应。

参数 类型 描述
 type  String 要触发的事件类型,例如‘click’。
 bubbles  Boolean  表示该事件是否能够被取消,针对鼠标事件模拟,该值应该被设置为true。
 cancelable  Boolean  表示该事件是被取消
 view  AbstractView  抽象视图:事件授予的视图,这个值几乎全是document.defaultView.
 detail  Intenger  附加的事件信息这个初始化时一般应该默认为0。
 screenX  Intenger  事件距离屏幕左边的X坐标
 screenY   Intenger  事件距离屏幕上边的y坐标
 clientX   Intenger  事件距离可视区域左边的X坐标
 clientY  Intenger  事件距离可视区域上边的y坐标
 ctrlKey   Boolean  代表ctrol键是否被按下,默认为false。
 altKey  Boolean  代表alt键是否被按下,默认为false。
 shiftKey  Boolean   Boolean类型 : 代表shif键是否被按下,默认为false
 metaKey  Boolean   代表meta key 是否被按下,默认是false
 button   Intenger  表示被按下的鼠标键,默认是零
 relatedTarget  Elment  事件的关联对象只有在模拟mouseover 和 mouseout时用到

使用方法如下:

var btn=document.getElementById("mybtn");
var event=document.createEvent("MouseEvent");
event.initMouseEvent("click",true,true,document.defaultView,0,0,0,0,0,false,false,false,false,0,null);
btn.dispatchEvent(event); //在这一步会设置event.target,以及触发事件类型

IE浏览器模拟鼠标事件

   var event=document.createEventObject();
event.screenX=100;
event.screenY=100;
event.clientX=100;
event.clientX=100;
event.ctrlKey=false; btn.fireEvent("onclick",event); //在这一步会设置event.serElement,以及触发事件类型

4.2.模拟键盘事件

键盘模拟事件是在DOM3规范中定义的。火狐浏览器根据草案定义了DOM2级中模拟键盘事件。在这里,我们讲述的是DOM3级规范,DOM3级不提倡使用oneypress事件。

 DOM3标准

 创建键盘事件的方法是createEvent()传入字符串“KeyboardEvent”.返回的对象有initKeyEvent()方法,这个方法有以下参数:

参数 类型 描述
type  String 要触发的事件类型,例如"keydown".
bubbles  Boolean  表示该事件是否能够被取消,针对鼠标事件模拟,该值应该被设置为true。
cancelable  Boolean  表示该事件是被取消
view  AbstractView 被授予事件的是图. 通常值为:document.defaultView. 
key string   按下的键对应的code. 
location integer  按下键所在的位置. 0 :默认键盘, 1 左侧位置, 2 右侧位置, 3 数字键盘区, 4 虚拟键盘区, or 5 游戏手柄. 
modifiers   Boolean  一个有空格分开的修饰符列表. 
repeat   integer 一行中某个键被按下的次数

使用方式:

var textbox=document.getElementById("myTextBox"),event;
if(document.implementation.hasFeature("KeyboardEvent",3.0)){
event=document.createEvent("KeyboardEvent");
event.initKeyboardEvent("keydown",true,true,document.defaultView,"a",0,"shift",0);
textbox.dispatchEvent(event);
}

并非所有的浏览器都实现了DOM3标准,下面看一下各个浏览器时怎么模拟鼠标事件。

FF浏览器

在FireFox中,调用createEvent()并传入KeyEvents就可以创建一个键盘事件。返回的事件对象会包含一个initKeyEvent()方法,这个方法接受一下10个参数。

参数 类型 描述
type  String 要触发的事件类型,例如"keydown".
bubbles  Boolean  表示该事件是否能够被取消,针对鼠标事件模拟,该值应该被设置为true。
cancelable  Boolean  表示该事件是被取消
view  AbstractView 被授予事件的是图. 通常值为:document.defaultView. 
ctrlKey   Boolean 表示是否按下了ctrl键位,默认值 false. 
altKey   Boolean 表示是否按下了altl键位,默认值 false
shiftKey   Boolean 表示是否按下了shift键位,默认值 false. 
metaKey  Boolean 表示是否按下了meta键位,默认值 false. 
KeyCode  Intenger 被按下或者被释放的键位. 这个参数对keydown和keyup有用 
charCode  Intenger 通过按键生成的ASCII编码. 这个参数对keypress有用
    //只适用于FF浏览器,在火狐浏览器中会在文本框中显示A 
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);

非火狐非IE浏览器

  在其他浏览器中,则需要创建一个通用事件,然后再向通用事件中添加键盘事件的特有信息。

    //在其他浏览器中不能输入文本,这是因为非浏览器创建的事件并不能精确的模拟事件。
//创建事件对象
var event=document.createEvent("Events");
//初始化事件对象
event.initEvent(type,bubble,cancelable); //初始化事件信息
event.view=document.defaultView;
event.altKey=false;
event.ctrlKey=false;
.....
event.keyCode=65;
event.charCode=65;
   //触发事件
textbox.dispatchEvent(event);

IE浏览器 

IE浏览器创建键盘事件和创建鼠标事件有点类似。如下所示:

  var event=document.createEventObject();
event.altKey=false;
event.ctrlKey=false;
event.shiftKey=false;
event.keyCode=65;
textbox.fireEvent("onkeydown",event);

4.3.自定义DOM事件

DOM3级还定义了"自定义事件"。自定义事件不同时DOM原生触发的,它的目的是让开发人员创建自己的事件。要创建新的自定义事件;

 非IE浏览器

可以调用createEvent("CustomEvent")返回的对象有一个名为initCustomEvent()方法,接受如下四个参数:

参数 类型 描述
type  String 要触发的事件类型,例如"keydown".
bubbles  Boolean  表示该事件是否能够被取消,针对鼠标事件模拟,该值应该被设置为true。
cancelable  Boolean  表示该事件是被取消
detail  Boolean 保存在event对象的detail属性中
//文档结构
<!DOCTYPE HTML>
<html>
<body>
<div>
<button id="button">click</button>
<input type="text" id="inputText"/>
</div>
</body>
</html>
 //节本     
var input=document.getElementById("inputText");
EventUtil.addEventListener(input,"myevent",function(event){
event=EventUtil.getEvent(event);
alert(event.detail.message); //访问detail中的信息
});//注册时事件 var button=document.getElementById("button");
button.onclick=function(){
if(document.implementation.hasFeature("CustomEvents","3.0")){
var event=document.createEvent("CustomEvent");
event.initCustomEvent("myevent",true,false,{message:"helloworld"});
input.dispatchEvent(event);
} //通过button按钮触发事件
}

IE浏览器自定义事件

//IE中document.createEventObject()方法不支持自定义的DOM事件....我们在有些前端框架中之所有能够实现自定义事件的各种浏览器兼容都是因为他们内部重写了一套事件机制来控制,才使得我们可以在各个浏览器上自定义事件。

JavaScript系列----事件机制的更多相关文章

  1. JavaScript的事件机制

    JavaScript的事件机制 摘要 事件是将JavaScript脚本与网页联系在一起的主要方式,是JavaScript中最重要的主题之一,深入理解事件的工作机制以及它们对性能的影响至关重要.本文将详 ...

  2. 深入研究JavaScript的事件机制

    本篇开始将回顾下Javascript的事件机制.同时会从一个最小的函数开始写到最后一个具有完整功能的,强大的事件模块.为叙述方便将响应函数/回调函数/事件Listener/事件handler都称为事件 ...

  3. 从八道面试题看JavaScript DOM事件机制

    As we all know,事件机制其实很简单,无非冒泡和捕获这两点,笔者不再赘述,网上相关文章一大堆,下面让我们直接看面试题 题目一到七,统一设置css .test2 { height: 50px ...

  4. JavaScript系列----AJAX机制详解以及跨域通信

    1.Ajax 1.1.Ajax简介 Ajax简介这一部分我们主要是谈一下ajax的起源,ajax是什么?因为这些是跟技术无关的.所以,大多细节都是一笔带过. Ajax的起源? Ajax一词源于2005 ...

  5. addEventListener和JavaScript的事件机制

    JavaScript的事件处理分为两个阶段: 捕获阶段:从根节点向event.target层层传递 冒泡阶段:从event.target向根节点层层传递 addEventListener(eventN ...

  6. javascript的事件机制(百度文库)

    http://wenku.baidu.com/view/9c8761e1524de518964b7d65.html http://wenku.baidu.com/view/1c3d7228bd6478 ...

  7. 【探讨】javascript事件机制底层实现原理

    前言 又到了扯淡时间了,我最近在思考javascript事件机制底层的实现,但是暂时没有勇气去看chrome源码,所以今天我来猜测一把 我们今天来猜一猜,探讨探讨,javascript底层事件机制是如 ...

  8. 【初窥javascript奥秘之事件机制】论“点透”与“鬼点击”

    前言 最近好好的研究了一番移动设备的点击响应速度,期间不断的被自己坑,最后搞得焦头烂额,就是现在可能还有一些问题,但是过程中感觉自己成长不少, 最后居然感觉对javascript事件机制有了更好的认识 ...

  9. 对JavaScript事件机制的一点理解

    JavaScript通过事件机制实现了异步操作,这种异步操作可以使CPU可以在IO任务的等待中被释放出来处理其他任务,等待IO结束再去处理这个任务.这个是一个基本的事件机制. 那么是不是说事件从监听到 ...

随机推荐

  1. Day2 python基础学习

    http://www.pythondoc.com/ Python中文学习大本营 本节内容: 一.字符串操作 二.列表操作 三.元组操作 四.字典操作 五.集合操作 六.字符编码操作 一.字符串操作 1 ...

  2. Android签名机制---签名过程

    大神文章:http://blog.csdn.net/jiangwei0910410003/article/details/50402000 一.知识点 1.数据摘要(数据指纹).签名文件,证书文件 2 ...

  3. js基于谷歌地图API绘制可编辑圆形与多边形

    之前的工作中需要在谷歌地图上绘制可编辑多边形区域,所以基于谷歌地图API封装了个html页面,通过调用js绘制多边形并返回各点的经纬度坐标:当然首先你要保证你的电脑可以打开谷歌地图... 新建一个ht ...

  4. 【转】Windows自动连接、断开无线网络

    前提是先连接到指定的WiFi网络上. 然后通过 netsh wlan export profile 将网络配置文件导出,然后使用如下命令添加配置文件到指定的网络接口上,再执行连接命令即可. netsh ...

  5. Python接口自动化——soap协议传参的类型是ns0类型的要创建工厂方法纪要

    1:在Python接口自动化中,对于soap协议的xml的请求我们可以使用Suds Client来实现,其soap协议传参的类型基本上是有2种: 第一种是传参,不需要再创建啥, 第二种就是ns0类型的 ...

  6. asp.net(C#)html无限分类树 可新增 删除 修改

    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="ProductSort.aspx ...

  7. spring两大核心对象IOC和AOP(新手理解)

    现在自己对spring的理解是:spring的主要的作用是用来进行业务的处理和实现类与类之间的解耦. 其中实现解耦功能 是IOC(控制反转)通过sessionfactory工厂来为需要的对象注入对应的 ...

  8. SqlBulkCopy效率低下原因分析

    看到标题 应该会奇怪 SqlBulkCopy 为什么会效率低下 场景:接手项目 数据库SQLSERVER2008R2,  目前有一张流水表单表数据超过4亿,表中建有索引,有其他模块对这个表进行查询操作 ...

  9. MYSQL数据库引擎区别详解

    数据库引擎介绍 MySQL数据库引擎取决于MySQL在安装的时候是如何被编译的.要添加一个新的引擎,就必须重新编译MYSQL.在缺省情况下,MYSQL支持三个引擎:ISAM.MYISAM和HEAP.另 ...

  10. 带你领会 线性代数 微积分的本质 3blue1brown 动画效果帅出天际

    前段时间在 哔哩哔哩 上偶然发现了 3blue1brown 精美的动画,配上生动的讲解,非常适合帮助建立数学的形象思维 其中两大系列,非常值得反复观看: 线性代数的本质(Essence of line ...