javascript 事件详解

首先要知道什么事事件流。事件流是从页面中接收事件的顺序。但是在这个问题的处理上,IE和Netscape提出了差不多完全相反的事件流概念。IE的事件流是冒泡流,而 Netscape的事件流是捕获流。
冒泡流就是有最具体的元素接收,然后逐级向上传播到不具体的节点(文档)。
捕获流就是不太具体的节点先收到事件,然后向下传递,最具体的节点最后接收到事件,用意在于事件到达目标之前捕获它。
目前的主流浏览器都支持冒泡流和捕获流。老浏览器不支持事件捕获。

DOM事件流
DOM2级事件规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段 和事件冒泡阶段。首先发生的是事件捕获,为截获事件提供了机会。然后是实际的目标接收到事件。最后一个阶段是冒泡阶段,可以在这个阶段对事件做出响应。
现在大多数浏览器都会支持在捕获阶段会触发和运行事件。


事件处理程序
第一种方式:在元素标签上直接进行绑定
     好处:简单,方便
     坏处:运行时存在时差问题;在不同的浏览器,处理程序的作用域链会不同,结果也会不同
第二种方式 :DOM级事件处理:将处理函数赋值给一个事件处理程序属性
     好处:简单,方便,易处理
     坏处:可能会出现时间差问题
第三种方式:DOM2级事件处理:指定了专门操作事件的函数
     好处:稍微复杂,绑定多个处理程序
     坏处:解决兼容性问题,作用域改变this值变化

DOM2事件的处理方法:addEventListener()和removeEventListener().它们都接受3个参数,要处理的事件名,作为事件处理程序的函数,一个布尔值。最后的布尔值为true,表示在事件捕获阶段调用事件处理程序,如果是false,表示在事件冒泡阶段调用事件的处理程序。
事件添加成功后,想要移除,必须做到移除函数的参数和添加函数的参数必须完全一致。这要求事件处理函数不能是匿名函数。代码示例如下:
var btn=document.getElementById("btn");
var handler=function(){
   alert(this.id);
}
btn.addEventListener("click",handler,false);
//other code here
btn.removeEventListener("click",handler,false);

IE事件的处理方法:attachEvent()和detachEvent()方法。它们都接收两个参数,事件处理程序名称与事件处理程序函数。 IE的IE8以前版本只支持冒泡事件流。 在IE中运行绑定事件的方法attachEvent()方法,处理函数中的this会是window对象。示例代码如下:
var btn=document.getElementById("btn");
var handler=function(){
   alert("Cilcked");
};
btn .attachEvent("onclick",handler);
//other code here
btn.detachEvent("onclick",handler);

跨浏览器的事件处理程序,只是冒泡流的封装处理程序
var EventUtil={
   addHandler:function(element,type,handler){
      if(element.addEventListener){
  element.addEventListener(type,handler,false); 
  }else if(element.attachEvent){
   element.attachEvent("on"+type,handler);
  }else{
   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); 
   }else{
    element["on"+type]=null; 
   }
}
};


事件对象
下面是W3C中列出的相关event的属性

标准 Event 属性

下面列出了 2 级 DOM 事件标准定义的属性。

属性描述IEFOW3C
bubbles返回布尔值,指示事件是否是起泡事件类型。No19Yes
cancelable返回布尔值,指示事件是否可拥可取消的默认动作。No19Yes
currentTarget返回其事件监听器触发该事件的元素。No19Yes
eventPhase返回事件传播的当前阶段。   Yes
target返回触发此事件的元素(事件的目标节点)。No19Yes
timeStamp返回事件生成的日期和时间。No19Yes
type返回当前 Event 对象表示的事件的名称。619Yes

标准 Event 方法

下面列出了 2 级 DOM 事件标准定义的方法。IE 的事件模型不支持这些方法:

方法描述IEFOW3C
initEvent()初始化新创建的 Event 对象的属性。No19Yes
preventDefault()通知浏览器不要执行与事件关联的默认动作。No19Yes
stopPropagation()终止事件在传播过程的捕获、目标处理或起泡阶段进一步传播。调用该方法后,该节点上处理该事件的处理程序将被调用,事件不再被分派到其他节点。No19Yes

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){
   switch(event.type){
     case "click": alert("Clicked");
                 break;
 case  "mouseover":event.target.style.backgroundColor="red";
                 break;
 case  "mouseout":event.target.style.backgroundColor="";
                  break;    
   }
};
btn.οnclick=handler;
btn.οnmοuseοver=handler;
btn.οnmοuseοut=handler;
在DOM事件机制中,阻止默认事件的方法是preventDefault()。示例如下
var link=docuemnt.getElementById("mylink");
link.οnclick=function(event){
    event.preventDefault();
};
只有当cancelable属性设置为true的事件,才可以使用preventDefault()来取消默认行为。
另外,stopPropagation()方法用于立即停止事件在DOM层中的传播,取消进一步的捕获和冒泡。使用方法:
var link=docuemnt.getElementById("mylink");
link.οnclick=function(event){
    event.syopPropagation();
};
event.eventPhase属性是确定事件正处在事件流的那个阶段。

IE中的事件对象
IE中的对象有几种不同的方式,取决于指定事件处理程序的方法。在使用DOM级方法添加事件处理程序时,event对象作为window对象的属性存在。如果事件处理程序使用的是attachEvent()方法添加的,event会作为一个对象传入的。
获取事件的目标,使用this有可能会出问题,最好使用event.srcElement来获取.
event.returnValue属性相当于DOM中的preventDefault()方法,设为false则阻止默认行为.
由于IE不支持事件捕获,只能设置event.cancelBubble()属性为true阻止后续的冒泡,默认是false。

跨浏览器的事件对象
为了兼容浏览器的事件处理,我们继续扩展EventUtil对象,使它成为事件处理的封装兼容类。
var 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);
  }else{
   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); 
   }else{
    element["on"+type]=null; 
   }
},
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){
    event.preventDefault();
   }else{
    event.returnValue=false; 
   }
},
     
stopPropagation:function(event){  // stop event bubble
  if(event.stopPropagation){
    event.stopPropagation();
   }else{
    event.cancelBubble=true;   
}
};
注意:这里面只是对起泡过程的封装,但是对捕获阶段没有处理,处理捕获阶段的方法请单独参阅DOM的事件处理。


事件类型
DOM3级事件的类型
UI事件:用户与页面的元素交互时触发
焦点事件:当元素获取焦点或失去焦点的时候触发
鼠标事件:用户通过鼠标在页面上执行操作时触发
滚轮事件:当使用滚轮时触发
文本事件:在文档中输入文本时触发
键盘事件:用户通过键盘在页面上执行操作时触发
合成事件:当为输入法编辑器输入字符时触发
变动事件:当底层的DOM结构发生改变时触发


UI事件
load:在页面加载完,window上触发;在框架集加载完,在框架集上触发;在图像加载完,在图像上触发;嵌入内   
           容加载完,在<object>上触发。
unload:当页面完全卸载后,在window上触发;所有框架集都卸载后在框架集上触发;所有的内嵌内容卸载后,在 
            <object>上触发.
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");
load事件,下面是一段示例代码:
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);
image.src="smile.gif";
});

unload事件,resize事件推荐采用上面的方式绑定事件
scroll事件,在window元素上发生,但它实际上是页面上相应元素的变化。
EventUtil.addHandler(window,"scroll",function(event){ 
 if(document.compatMode=="CSS1Compat") {
 alert(document.documentElement.scrollTop);
 }else{
 alert(document.body.scrollTop);
 } });
resize事件和scroll事件会有重复触发的效果,但是通过一些方式可以消除重复触发的效果。
javascript  在window.onresize的时候防止重复响应和提交

function doResize(){
  alert("width="+document.documentElement.clientWidth + "   Height="+document.documentElement.clientHeight);
}
var ajaxResize=function(resettime){
var  resizeTimer = null;
return function(){
var settime;
if(resettime){
settime=resettime;
}else{
settime=1000;
}
           if(resizeTimer) clearTimeout(resizeTimer);
           resizeTimer = setTimeout("doResize()",settime);
}
}
window.onresize = ajaxResize();

焦点事件
焦点事件会在页面获得或失去焦点时触发。利用这些事件与document.hasFocus()方法及document.activeElement属性配合,可以知晓用户在页面上的行踪。有以下6个焦点事件:
blur:失去焦点
focus:获取焦点
focusin:元素获取焦点时触发,支持冒泡
focusout:元素失去焦点时触发,支持冒泡
要确定浏览器是否支持这些事件,可以使用下面的代码进行检测
var isSupported=document.implementation.hasFeature("FocusEvent","3.0");

鼠标与滚轮事件
DOM3事件中定义了9个鼠标事件。
click:用户点击鼠标或者按下回车键时触发。
dblclick:用户双击鼠标左键时触发
mousedown:在用户按下了任意鼠标按钮时触发
mouseenter:当鼠标的光标从元素外部首次移动到元素范围内时触发。这个事件不会冒泡
mouseleave:在位于元素上方的鼠标光标移动到元素范围之外时触发。这个事件不会冒泡
mousemove:在鼠标指针在元素内部移动时频繁触发。不能通过键盘触发。
mouseout:在鼠标指针位于一个元素上方,然后用户将其移入其它元素是触发。
mouseover:在鼠标指针位于一个元素外部,然后用户将其首次移入另一个元素边界之内时触发
mouseup:在用户释放鼠标按钮时触发。
只有在同一个元素上相继触发mousedown和mouseup事件,才会触发click事件。只有连续触发两次click事件,才会触发dblclick。
检测浏览器是否支持DOM2以上的事件,可以使用以下代码:
var isSupported=document.implementation.hasFeature("MouseEvents","2.0");
检测浏览器是否支持DOM3以上的鼠标事件
var isSupported=document.implementation.hasFeature("MouseEvent","3.0");
鼠标事件中还有一类是滚轮事件,mousewheel事件。

鼠标事件详解
1.鼠标事件
由于鼠标事件是在浏览器窗口中特定位置发生的,所以这个位置信息保存在事件对象的clientX,cilentY属性中。所有浏览器都支持这个两个属性。
window.οnlοad=function(){
var testd=document.getElementById("testdiv");
console.log(testd);
EventUtil.addHandler(testd,"click",function(event){
                             event=EventUtil.getEvent(event);
 alert("Client coordinates:"+event.clientX+","+event.clientY);
                             });
}
同样的获取screenX,screenY属性,相对于整个屏幕的位置
2.页面坐标位置
为了兼容IE8之前的版本,可以使用下面的响应函数
function(event){
 event=EventUtil.getEvent(event);
         var pageX=event.pageX,pageY=event.pageY;
         if(pageX==undefined){
              pageX=event.clientX+(document.body.scrollLeft||document.documentElement.scrollLeft);
         }
        if(pageY==undefined){
             pageY=event.clientY+(document.body.scrollTop||document.documentElement.scrollTop);
        }
 alert("Client coordinates:"+event.clientX+","+event.clientY);
 });
3.修改热键
虽然鼠标事件主要是使用鼠标触发的,但是按下鼠标时键盘上一些键的状态也会改变。这些键就是Shift,Ctrl,Alt,Meta(在window键盘中是Window键,苹果机中是Cmd键),它们经常被uyonglai修改鼠标事件的行为。这些键按下的时候,保存的布尔值会发生变化。当鼠标事件发生时,通过检测下面的属性可以确定用户是否同时按下了其中的键。
var test=document.getElementById("testdiv");
EventUtil.addHandler(test,"click",function(event){
event=EventUtil.getEvent(event);
var keys=new Array();
if(event.shiftKey){
  keys.push("shift");
}
if(event.ctrlKey){
  keys.push("ctrl"); 
}
if(event.altKey){
  keys.push("alt");
}
if(event.metaKey){
  keys.push("meta");
}
alert("keys:"+keys.join(","));
   });
4相关元素
DOM通过event对象提供了relatedTarget属性提供了相关元素的信息。这个属性只对于mouseover和mouseout事件才包含值;对于其他事件,这只属性的值是null。IE中为mouseover提供了fromElement保存想关元素,为mouseout提供了toElement保存相关元素。下面把获取相关元素的代码添加到EventUtil对象中:
getRelatedTarget:function(event){
     if(event.relatedTarget){
 return event.relatedTarget;//DOM
 }else if(event.toElement){
 return event.toElement;    //IE mouseover
 }else if(event.fromElement){
     return event.fromElement;   //IE mouseout 
 }else{
     return null;  
 }
}
5鼠标按钮
只有主鼠标按钮被单击是才会触发click事件,因此检测鼠标按钮并不是必要的。但是对于mousedown和mouseup事件来说,则在其event对象存一个button属性的,表示按下或者释放按钮。但是IE的按钮
事件又太过复杂,于是,可以使用下面的代码进行兼容。
getButton:function(event){
   if(document.implementation.hasFeature("MouseEvents","2.0")){
   return event.button;
}else{
   switch(event.button){
      case 0:
  case 1:
  case 3:
  case 5:
  case 7:
       return 0;
  case 2:
  case 6:
       return 2;
  case 4:
       return 1;
   }
    }
}
对于鼠标事件来说,detail中包含了一个数值,表示在给定位置上发生了多少次单击,移动后清零。
6鼠标滚轮事件
滚轮事件的名称是mousewheel,这个时间的对象event除了包含标准信息意外,还包含一个特殊属性wheelDelta,它记录了鼠标的滚动倍数。在FireFox中类似的事件名称是DOMMouseScroll,保存信息的属性是detail。下面是解决鼠标滚轮事件获取滚动倍数的兼容代码
getWheelDelta:function(event){
  if(event.wheelDelta){
  return (client.engine.opera&&client.engine.opera<9.5?-event.wheelDelta:event.wheelDelta);
  }else{
 return -event.detail*40;   
  }
}
7.触摸设备
触摸设备不支持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,表示把文本输入到文本框中的方式。
0:表示浏览器不确定是怎么输入的
1:表示使用键盘输入的
2:表示文本是粘贴进来的
3:表示文本是拖放进来的
4:表示文本是使用IME输入的
5:表示文本是通过在表单中选择一项输入的
6:表示文本是通过手写输入的
7:表示文本是通过语音输入的
8:表示文本是通过几种方法组合输入的
9:表示文本是通过脚本输入的

复合事件是DOM3级事件中新添加的一类事件,用于IME的输入序列。它可以让用户输入在物理键盘上找不到的字符。复合事件有以下三个:
compositionstart:在IME的文本复合系统打开时触发,表示要开始输入。
compositionupdate:在向输入字段中插入新字符时触发
compositionend:在IME的文本复合系统关闭时触发,表示返回正常键盘输入状态。
目前只有IE9以上的版本支持。

变动事件
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){
   switch(event.type){
     case "click": alert("Clicked");
                 break;
 case  "mouseover":event.target.style.backgroundColor="red";
                 break;
 case  "mouseout":event.target.style.backgroundColor="";
                  break;    
   }
};
btn.οnclick=handler;
btn.οnmοuseοver=handler;
btn.οnmοuseοut=handler;
减少处理程序的个数,降低内存的消耗

在不需要事件处理的时候,可以考虑使用移除事件来降低内存的开销。在页面卸载之前,先通过onunload事件处理程序移除所有事件处理程序。

模拟事件可以让用户自己去模拟一些事件,这种方式在测试web应用程序时非常有用,现在大部分的主流浏览器都支持它。


自定义DOM事件,目的是让开发人员自行定义自己的事件。创建方法为createEvent("CustomEvent"),返回的对象有一个名为initCustomEvent()的方法,接收4个参数:
type:字符串,触发事件的类型
bubble:布尔值,表示事件是否应该冒泡
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);
}






  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值