本文共 12834 字,大约阅读时间需要 42 分钟。
首先要知道什么事事件流。事件流是从页面中接收事件的顺序。但是在这个问题的处理上,IE和Netscape提出了差不多完全相反的事件流概念。IE的事件流是冒泡流,而 Netscape的事件流是捕获流。 冒泡流就是有最具体的元素接收,然后逐级向上传播到不具体的节点(文档)。
捕获流就是不太具体的节点先收到事件,然后向下传递,最具体的节点最后接收到事件,用意在于事件到达目标之前捕获它。
目前的主流浏览器都支持冒泡流和捕获流。老浏览器不支持事件捕获。
DOM2级事件规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段 和事件冒泡阶段。首先发生的是事件捕获,为截获事件提供了机会。然后是实际的目标接收到事件。最后一个阶段是冒泡阶段,可以在这个阶段对事件做出响应。
现在大多数浏览器都会支持在捕获阶段会触发和运行事件。
坏处:运行时存在时差问题;在不同的浏览器,处理程序的作用域链会不同,结果也会不同
第二种方式 :DOM级事件处理:将处理函数赋值给一个事件处理程序属性
第三种方式:DOM2级事件处理:指定了专门操作事件的函数
DOM2事件的处理方法:addEventListener()和removeEventListener().它们都接受3个参数,要处理的事件名,作为事件处理程序的函数,一个布尔值。最后的布尔值为true,表示在事件捕获阶段调用事件处理程序,如果是false,表示在事件冒泡阶段调用事件的处理程序。
事件添加成功后,想要移除,必须做到移除函数的参数和添加函数的参数必须完全一致。这要求事件处理函数不能是匿名函数。代码示例如下:
var btn=document.getElementById("btn");
btn.addEventListener("click",handler,false);
btn.removeEventListener("click",handler,false);
IE事件的处理方法:attachEvent()和detachEvent()方法。它们都接收两个参数,事件处理程序名称与事件处理程序函数。
IE的IE8以前版本只支持冒泡事件流。 在IE中运行绑定事件的方法attachEvent()方法,处理函数中的this会是window对象。示例代码如下:
var btn=document.getElementById("btn");
btn
.attachEvent("onclick",handler);
btn.detachEvent("onclick",handler);
addHandler:function(element,type,handler){
if(element.addEventListener){
element.addEventListener(type,handler,false);
}else if(element.attachEvent){
element.attachEvent("on"+type,handler);
element["on"+type]=handler;
removeHandler:function(element,type,handler){
if(element.removeEventListener){
element.removeEventListener(type,handler,false);
}else if(element.detachEvent){
element.detachEvent("on"+type,handler);
标准 Event 属性
下面列出了 2 级 DOM 事件标准定义的属性。
属性 | 描述 | IE | F | O | W3C |
| 返回布尔值,指示事件是否是起泡事件类型。 | No | 1 | 9 | Yes |
| 返回布尔值,指示事件是否可拥可取消的默认动作。 | No | 1 | 9 | Yes |
| 返回其事件监听器触发该事件的元素。 | No | 1 | 9 | Yes |
| 返回事件传播的当前阶段。 | | | | Yes |
| 返回触发此事件的元素(事件的目标节点)。 | No | 1 | 9 | Yes |
| 返回事件生成的日期和时间。 | No | 1 | 9 | Yes |
| 返回当前 Event 对象表示的事件的名称。 | 6 | 1 | 9 | Yes |
标准 Event 方法
下面列出了 2 级 DOM 事件标准定义的方法。IE 的事件模型不支持这些方法:
方法 | 描述 | IE | F | O | W3C |
| 初始化新创建的 Event 对象的属性。 | No | 1 | 9 | Yes |
| 通知浏览器不要执行与事件关联的默认动作。 | No | 1 | 9 | Yes |
| 终止事件在传播过程的捕获、目标处理或起泡阶段进一步传播。调用该方法后,该节点上处理该事件的处理程序将被调用,事件不再被分派到其他节点。 | No | 1 | 9 | Yes |
IE 属性
IE 并不支持(至少在 IE 7 中)标准的 DOM 事件模型,并且 IE 的 Event 对象定义了一组完全不同的属性。
IE 事件模型并没有为不同的事件定义继承层级,因此所有和任何事件的类型相关的属性都在这里列出。
属性 | 描述 |
cancelBubble | 如果事件句柄想阻止事件传播到包容对象,必须把该属性设为 true。 |
fromElement | 对于 mouseover 和 mouseout 事件,fromElement 引用移出鼠标的元素。 |
keyCode | 对于 keypress 事件,该属性声明了被敲击的键生成的 Unicode 字符码。 对于 keydown 和 keyup 事件,它指定了被敲击的键的虚拟键盘码。 虚拟键盘码可能和使用的键盘的布局相关。 |
offsetX,offsetY | 发生事件的地点在事件源元素的坐标系统中的 x 坐标和 y 坐标。 |
returnValue | 如果设置了该属性,它的值比事件句柄的返回值优先级高。 把这个属性设置为 fasle,可以取消发生事件的源元素的默认动作。 |
srcElement | 对于生成事件的 Window 对象、Document 对象或 Element 对象的引用。 |
toElement | 对于 mouseover 和 mouseout 事件,该属性引用移入鼠标的元素。 |
x,y | 事件发生的位置的 x 坐标和 y 坐标,它们相对于用 CSS 动态定位的最内层包容元素。 |
通过一个函数处理多个事件时,可以使用type属性。
var btn=document.getElementById("myBtn");
var handler=function(event){
case "click": alert("Clicked");
case "mouseover":event.target.style.backgroundColor="red";
case "mouseout":event.target.style.backgroundColor="";
在DOM事件机制中,阻止默认事件的方法是preventDefault()。示例如下
var link=docuemnt.getElementById("mylink");
link.οnclick=function(event){
只有当cancelable属性设置为true的事件,才可以使用preventDefault()来取消默认行为。
另外,stopPropagation()方法用于立即停止事件在DOM层中的传播,取消进一步的捕获和冒泡。使用方法:
var link=docuemnt.getElementById("mylink");
link.οnclick=function(event){
event.eventPhase属性是确定事件正处在事件流的那个阶段。
IE中的对象有几种不同的方式,取决于指定事件处理程序的方法。在使用DOM级方法添加事件处理程序时,event对象作为window对象的属性存在。如果事件处理程序使用的是attachEvent()方法添加的,event会作为一个对象传入的。
获取事件的目标,使用this有可能会出问题,最好使用event.srcElement来获取.
event.returnValue属性相当于DOM中的preventDefault()方法,设为false则阻止默认行为.
由于IE不支持事件捕获,只能设置event.cancelBubble()属性为true阻止后续的冒泡,默认是false。
为了兼容浏览器的事件处理,我们继续扩展EventUtil对象,使它成为事件处理的封装兼容类。
addHandler:function(element,type,handler){ //add event
if(element.addEventListener){
element.addEventListener(type,handler,false);
}else if(element.attachEvent){
element.attachEvent("on"+type,handler);
element["on"+type]=handler;
removeHandler:function(element,type,handler){ //remove event
if(element.removeEventListener){
element.removeEventListener(type,handler,false);
}else if(element.detachEvent){
element.detachEvent("on"+type,handler);
getEvent:function(event){ // get event object
return event?event:window.event;
getTarget:function(event){
return event.target||event.srcElement;
preventDefault:function(event){ // stop default event
if(event.preventDefault){
stopPropagation:function(event){ // stop event bubble
if(event.stopPropagation){
注意:这里面只是对起泡过程的封装,但是对捕获阶段没有处理,处理捕获阶段的方法请单独参阅DOM的事件处理。
load:在页面加载完,window上触发;在框架集加载完,在框架集上触发;在图像加载完,在图像上触发;嵌入内
unload:当页面完全卸载后,在window上触发;所有框架集都卸载后在框架集上触发;所有的内嵌内容卸载后,在
abort:用户停止下载时;嵌入内容没有加载完,在<object>上触发
error:js发生错误,window触发;无法加载嵌入内容,<object>上触发;图像无法加载,在图像上触发;当框架集
select:当用户选择文本框中的一个或多个字符时触发
resize:当窗口或者框架的大小变化时在window或者框架上面触发
scroll:当用户滚动带滚动条的元素时,在带滚动条的元素上触发。
要确定浏览器是否支持DOM2事件规定的HTML事件,可以使用以下代码:
var isSupported=document.implementation.hasFeature("HTMLEvents","2.0");
要确定浏览器是否支持DOM3事件规定的HTML事件,可以使用以下代码:
var isSupported=document.implementation.hasFeature("UIEvent","3.0");
EventUtil.addHandler(window,"load",function(){
var image=document.getElementById("image");
EventUtil.addHandler(image,"load",function(event){
event=Eventutil.getEvent(event);
alert(EventUtil.getTarget(event).src);
document.body.appendChild(image);
unload事件,resize事件推荐采用上面的方式绑定事件
scroll事件,在window元素上发生,但它实际上是页面上相应元素的变化。
EventUtil.addHandler(window,"scroll",function(event){
if(document.compatMode=="CSS1Compat") {
alert(document.documentElement.scrollTop);
alert(document.body.scrollTop);
resize事件和scroll事件会有重复触发的效果,但是通过一些方式可以消除重复触发的效果。
javascript 在window.onresize的时候防止重复响应和提交
alert("width="+document.documentElement.clientWidth + " Height="+document.documentElement.clientHeight);
var ajaxResize=function(resettime){
if(resizeTimer) clearTimeout(resizeTimer);
resizeTimer = setTimeout("doResize()",settime);
window.onresize = ajaxResize();
焦点事件会在页面获得或失去焦点时触发。利用这些事件与document.hasFocus()方法及document.activeElement属性配合,可以知晓用户在页面上的行踪。有以下6个焦点事件:
要确定浏览器是否支持这些事件,可以使用下面的代码进行检测
var isSupported=document.implementation.hasFeature("FocusEvent","3.0");
mousedown:在用户按下了任意鼠标按钮时触发
mouseenter:当鼠标的光标从元素外部首次移动到元素范围内时触发。这个事件不会冒泡
mouseleave:在位于元素上方的鼠标光标移动到元素范围之外时触发。这个事件不会冒泡
mousemove:在鼠标指针在元素内部移动时频繁触发。不能通过键盘触发。
mouseout:在鼠标指针位于一个元素上方,然后用户将其移入其它元素是触发。
mouseover:在鼠标指针位于一个元素外部,然后用户将其首次移入另一个元素边界之内时触发
只有在同一个元素上相继触发mousedown和mouseup事件,才会触发click事件。只有连续触发两次click事件,才会触发dblclick。
检测浏览器是否支持DOM2以上的事件,可以使用以下代码:
var isSupported=document.implementation.hasFeature("MouseEvents","2.0");
var isSupported=document.implementation.hasFeature("MouseEvent","3.0");
鼠标事件中还有一类是滚轮事件,mousewheel事件。
由于鼠标事件是在浏览器窗口中特定位置发生的,所以这个位置信息保存在事件对象的clientX,cilentY属性中。所有浏览器都支持这个两个属性。
window.οnlοad=function(){
var testd=document.getElementById("testdiv");
EventUtil.addHandler(testd,"click",function(event){
event=EventUtil.getEvent(event);
alert("Client coordinates:"+event.clientX+","+event.clientY);
同样的获取screenX,screenY属性,相对于整个屏幕的位置
event=EventUtil.getEvent(event);
var pageX=event.pageX,pageY=event.pageY;
pageX=event.clientX+(document.body.scrollLeft||document.documentElement.scrollLeft);
pageY=event.clientY+(document.body.scrollTop||document.documentElement.scrollTop);
alert("Client coordinates:"+event.clientX+","+event.clientY);
虽然鼠标事件主要是使用鼠标触发的,但是按下鼠标时键盘上一些键的状态也会改变。这些键就是Shift,Ctrl,Alt,Meta(在window键盘中是Window键,苹果机中是Cmd键),它们经常被uyonglai修改鼠标事件的行为。这些键按下的时候,保存的布尔值会发生变化。当鼠标事件发生时,通过检测下面的属性可以确定用户是否同时按下了其中的键。
var test=document.getElementById("testdiv");
EventUtil.addHandler(test,"click",function(event){
event=EventUtil.getEvent(event);
alert("keys:"+keys.join(","));
DOM通过event对象提供了relatedTarget属性提供了相关元素的信息。这个属性只对于mouseover和mouseout事件才包含值;对于其他事件,这只属性的值是null。IE中为mouseover提供了fromElement保存想关元素,为mouseout提供了toElement保存相关元素。下面把获取相关元素的代码添加到EventUtil对象中:
getRelatedTarget:function(event){
return event.relatedTarget;//DOM
}else if(event.toElement){
return event.toElement; //IE mouseover
}else if(event.fromElement){
return event.fromElement;
//IE mouseout
只有主鼠标按钮被单击是才会触发click事件,因此检测鼠标按钮并不是必要的。但是对于mousedown和mouseup事件来说,则在其event对象存一个button属性的,表示按下或者释放按钮。但是IE的按钮
事件又太过复杂,于是,可以使用下面的代码进行兼容。
getButton:function(event){
if(document.implementation.hasFeature("MouseEvents","2.0")){
对于鼠标事件来说,detail中包含了一个数值,表示在给定位置上发生了多少次单击,移动后清零。
滚轮事件的名称是mousewheel,这个时间的对象event除了包含标准信息意外,还包含一个特殊属性wheelDelta,它记录了鼠标的滚动倍数。在FireFox中类似的事件名称是DOMMouseScroll,保存信息的属性是detail。下面是解决鼠标滚轮事件获取滚动倍数的兼容代码
getWheelDelta:function(event){
return (client.engine.opera&&client.engine.opera<9.5?-event.wheelDelta:event.wheelDelta);
触摸设备不支持dblclick事件,轻击可单元素触发mousemove事件,mousemove会触发mouseover和mouseout事件。两个手指在屏幕上随页面滚动时触发mousewheel和scroll事件。
不建议使用click以外的其他鼠标事件来展示功能或引发代码执行。不要使用ommouseover事件来向用户展示新选项。不要使用dblclick事件执行重要的操作。
键盘事件主要有三个:keydown,keypresss,keyup.keydown:按下键盘上的任意键都会触发,但是按住不放会重复触发。keypress:按下字符键是触发,不放开则重复触发,按下ESC键也会触发。keyup:当用户释放键盘上的键时触发。文本事件只有textInput事件,是对keypress的补充,用意是在文本显示给用户之前更用以拦截。
在键盘事件中的event对象有keyCode属性,它保存着字符的ASCII码值。在keypress事件中,event对象支持一个属性charCode,保存着按下字符的ASCII码。
textInput事件,主要考虑的是字符,因此它的event对象中包含一个data属性,这个属性的值就是用户输入的字符。event还有一个属性,叫inputMethod,表示把文本输入到文本框中的方式。
复合事件是DOM3级事件中新添加的一类事件,用于IME的输入序列。它可以让用户输入在物理键盘上找不到的字符。复合事件有以下三个:
compositionstart:在IME的文本复合系统打开时触发,表示要开始输入。
compositionupdate:在向输入字段中插入新字符时触发
compositionend:在IME的文本复合系统关闭时触发,表示返回正常键盘输入状态。
DOM2级的变动事件能在DOM中的部分发生变化时给出提示。变动事件是为了XML或者HTML DOM设计的,并不特定于那种语言。DOM2级定义了如下变动事件:
DOMSubtreeModified:在DOM结构中发生任何变化时触发。这个事件在其他任何事件触发后触发。
DOMNodeInserted:在一个节点作为子节点被插入到另一个节点中时触发
DOMNodeRemoved:在节点从其父节点中被移除时触发
DOMNodeInsertedIntoDocument:在一个节点被插入文档或通过子树间接插入文档后触发。在DOMNodeInserted之后触发
DOMNodeRemovedFromDocument:在一个节点被直接从文档中移除或通过子树间接从文档中移除之前触发。这个事件在DOMNodeRemoved之后触发
DOMAttrModified:在特性被修改之后触发
DOMCharacterDataModified:在文本节点的值发生变化时触发
var isSupported=document.implementation.hasFeature("MutationEvents","2.0");
var btn=document.getElementById("myBtn");
var handler=function(event){
case "click": alert("Clicked");
case "mouseover":event.target.style.backgroundColor="red";
case "mouseout":event.target.style.backgroundColor="";
在不需要事件处理的时候,可以考虑使用移除事件来降低内存的开销。在页面卸载之前,先通过onunload事件处理程序移除所有事件处理程序。
模拟事件可以让用户自己去模拟一些事件,这种方式在测试web应用程序时非常有用,现在大部分的主流浏览器都支持它。
自定义DOM事件,目的是让开发人员自行定义自己的事件。创建方法为createEvent("CustomEvent"),返回的对象有一个名为initCustomEvent()的方法,接收4个参数:
cancelable:布尔值,表示事件是否应该冒泡
detail:对象,任意值,保存在event对象的detail属性中
可以像分派其他事件一样分派自定义事件。下面是一个例子:
var div=document.getElementById("myDiv"),event;
EventUtil.addHandler(div,"myevent",function(event){
alert("DIV"+event.detail);
EventUtil.addHandler(document,"myevent",function(event){
alert("DOCUMENT:"+event.detail);
if(document.implementation.hasFeature("CustomEvents","3.0")){
event=document.createEvent("CustomEvent");
event.initCustomEvent("myevent",true,false,"Hello World!");
div.dispatchEvent(event);
转载地址:http://ddvdi.baihongyu.com/