所谓的标准事件流指的的: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); //在某一个元素上撤销已注册的事件。 这里强调的是 这里的函数必须与已注册的函数是同一个函数!
虽然大部分的浏览器都遵循着标准,但是在IE浏览器中,事件流却是非标准的。IE中事件流只有两个阶段: 处于目标阶段,冒泡阶段。
上面的HTML结构,如果是在IE中,事件流执行时如图所示:
对应着在IE中的事件注册和撤销事件函数:
target.attachEvent(type, listener); //target: 文档节点、document、window 或 xmlhttpRequest。 //函数参数: type----包含on.type一般为“onclick”,"onkeydown" // listener:事件触发时的回调函数。
target.detachEvent(type,listener); //参数与注册参数相对应。
因为,IE中事件流没有捕获阶段,所以相应的在注册事件和撤销事件时比标准注册事件少一个参数。
为什么要单独提出事件的执行顺序? 是因为一些事件有其默认的行为,比如在文本框中按下鼠标左键,文本框文本框获得焦点;点击一个超链接,超链接进行跳转。 那么,事件的执行顺序是怎样的呢?
一般事件的执行顺序: 事件的捕获阶段====>处于目标阶段====>事件的冒泡阶段====>事件的默认行为。
正因为事件的默认行为是最后执行的,我们才得以机会阻止事件的默认行为。
如下,阻止文本框获取焦点:
//阻止文本框获取焦点 var input=document.getElementById("inputText"); input.onmousedown=function(event){ event=event||window.event; if(event.preventDefault){ //非IE浏览器阻止事件默认行为 event.preventDefault(); }else{ event.returnValue=false;//IE浏览器阻止事件默认行为 } }
因为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; } }};
通过Javascript指定事件处理程序的传统方式,就是将一个函数赋值给一个事件处理程序的属性。这种为事件处理程序赋值的方法是在第四代Web浏览器中出现的,而且至今仍然为所有现在浏览器支持。原因主要有两点: 1.简单 2.具有跨浏览器优势。
每个元素(window和document)都有自己的事件处理程序属性,这些属性通常全部小写,例如 onclick, onmousedown.
var btn = document.getElementById('mybtn');btn.onclick = function () { alert('click');}
DOM0级事件有其自身的局限性,
1.那就是某一个属性只能赋值给一个函数,也就导致在某一个元素上的某一个事件属性只能对应着一个函数。多次注册时,已最 后一次注册为准。
2.DOM0级事件全部都是默认在冒泡阶段执行。
我们在第一部分所定义的跨浏览注册事件函数,就是一个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浏览器,我们还可以在事件的捕获阶段,注册事件,但是一般因兼容性考虑,我们很少在事件的捕获阶段注册事件。
在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含着所有事件有关的信息。
例如,单击事件中会包含鼠标的位置信息,键盘触发的事件中会包含按下的键位有关的信息。
所有的浏览器都支持event,但支持的方式却有不同。
属性 | 类型 | 读写 | 描述 |
---|---|---|---|
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则只包含事件的实际目标。
属性 | 类型 | 读写 | 描述 |
---|---|---|---|
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.属性.
因为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事件详解
非IE浏览器
创建鼠标事件的方法是createEvent()传入字符串“MouseEvent”.返回的对象有initMouseEvent()方法,这个方法有15个参数,分别与鼠标事件中某个典型的属性一一对应。