JavaScript系列----事件机制

1.事件流

1.1.标准事件流

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

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

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

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

事件触发一次经历三个阶段,因此咱们在一个元素上注册事件也就能够在对应阶段注册事件,移除事件也一样。浏览器

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中的事件注册和撤销事件函数:dom

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

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

1.3.事件的执行顺序

  为何要单独提出事件的执行顺序? 是由于一些事件有其默认的行为,好比在文本框中按下鼠标左键,文本框文本框得到焦点;点击一个超连接,超连接进行跳转。 那么,事件的执行顺序是怎样的呢?工具

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

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

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

//阻止文本框获取焦点  
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和标准浏览器的不一样,因此为了克服这样或者那样的问题,如今编写一个工具包克服兼容性的问题:

 1 var EventUtil =  {
 2         addEventListener: function (element, type, callback) {  //注册事件,由于浏览器的兼容性考虑,注册事件通常都是注册在事件的捕获阶段
 3             if (element.addEventListener) {
 4                 element.addEventListener(type, callback, false);
 5             } else if (element.attachEvent) {
 6                 element.attachEvent('on' + type, callback);
 7             } else {
 8                 element['on' + type] = callback;
 9             }
10         }, 
11         getEvent:function(event){           //获取事件 12             return event||window.event;
13         },                
14         getTarget:function(event){           //获取事件的触发目标 15             return event.target||event.srcElement;
16         },
17         preventDefault:function(event){        //阻止事件的默认行为 18             event.preventDefault?event.preventDefault():event.returnValue=false;
19         },
20         stopPropagation:function(event){          //阻止事件冒泡 21             event.stopPropagation?event.stopPropagation:event.cancelBubble=true;
22         },
23         removeEventListener: function(element, type, callback) {  //撤销事件
24             if (element.removeEventListener) {
25                 element.removeEventListener(type, callback, false);
26             } else if (element.detachEvent) {
27                 element.detachEvent('on' + type, callback);
28             } else {
29                 element['on' + type] = null;
30             }
31         }
32     };

 

每一个事件在其被触发时,都有一些其特有的属性,好比键盘事件会有键位信息,鼠标事件会有会有位置信息。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事件....咱们在有些前端框架中之全部可以实现自定义事件的各类浏览器兼容都是由于他们内部重写了一套事件机制来控制,才使得咱们能够在各个浏览器上自定义事件。

相关文章
相关标签/搜索