事件处理程序在应用中是必不可少的,虽然现在很多框架都有自己实现事件处理方法,但是熟知原生才能让我们应对各种各样的需求并且实现自己的想法
事件流
这个是很基本很基本的概念了
DOM2级事件规定的事件流包括三个阶段:
①事件捕获阶段
②处于目标阶段
③冒泡阶段
并且明确要求捕获阶段不会涉及事件目标
事件处理程序
这里主要讲DOM2级事件处理程序,HTML事件处理程序和DOM0级事件处理程序现在几乎很少接触,故跳过
DOM2级事件处理程序
addEventListener()
接收三个参数:①要处理的事件名②事件处理程序③布尔值(true表示捕获阶段调用时间处理程序(建议),false表示冒泡阶段)
removeEventListenser()
接收的参数与addEventListener一样,需要注意的是,通过addEventListener()添加的匿名函数将无法通过removeEventListener()移除
IE事件处理程序
addEventListener在IE8及更早版本都不给予支持,但有类似的两个方法:attachEvent()和detachEvent(),同样接收事件处理程序名称和事件处理程序函数作为参数,默认在冒泡阶段调用
注意:
①这里的时间处理程序名称没有on前缀
②这里的时间处理程序会在全局作用域中运行,故this等于window
跨浏览器的事件处理程序
var EventUtil = {
addHandler:function(element,type,handler){
if(element.addEventListener){
element.addEventListener(type,handler,false);
}else if(elment.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;
}
}
}
事件对象
事件对象包含着所有与时间有关的信息,包括导致事件的元素、事件的类型以及其他与特定时间相关的信息.事件对象又分为DOM事件对象和IE事件对象,下面将分开总结
DOM中的事件对象
兼容DOM的浏览器会将一个event对象传入到事件处理程序中,event对象包含与创建它的特定事件有关的属性和方法,不同事件类型不一样,不过所有事件都有下列共同的属性和方法
- bubbles 布尔值 表明事件是否冒泡
- cancelable 布尔值 表明是否可以取消事件的默认行为
- currentTarget 节点 其事件处理程序当前正在处理事件的那个元素
- defaultPrevented 布尔值 是否被阻止了默认操作
- detail Integer 与事件相关的细节
- eventPhase Integer 调用事件处理程序的阶段:1->捕获 2->处于目标 3->冒泡
- preventDefault() 取消事件的默认行为
- stopImmediatePropagation() 取消事件的进一步捕获或冒泡同时阻止任何事件处理程序被调用(DOM3)
- stopPropagation() 取消事件的进一步捕获或冒泡
- target 节点 事件的目标
- trusted 布尔值 是否为浏览器生成的
- type 被触发的事件的类型
- view 与事件关联的抽象视图
注意:在事件处理程序内部,对象this始终等于currentTarget,即相应事件的元素,而不一定是触发事件的元素,而event.target则指向触发事件的元素
IE中的事件对象
要访问IE中的event对象的方式取决于指定事件处理程序的方法:
①使用DOM0级添加事件处理程序时,event对象作为window对象的一个属性存在
②使用attachEvent()添加的事件处理程序,会有一次event传入事件函数中
③通过HTML特性制定的事件处理程序,可以通过一个叫event的变量来访问event对象
IE的event对象同样包含与创建它的事件相关的属性和方法,但所有事件对象都会包含下面所列的属性和方法
- cancelBubble 布尔值 默认false,设置为true可以取消事件冒泡
- returnValue 布尔值 默认true,但将其设置为false可以取消事件的默认行为
- srcElement 事件的目标,与DOM中的target属性相同
- type 被触发的事件的类型
跨浏览器的事件对象
var EventUtil = {
addHandler:function(element,type,handler){
if(element.addEventListener){
element.addEventListener(type,handler,false);
}else if(elment.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;
}
},
getEvent:function(event){
return event? event: window.event;
},
getTarget:function(event){
return event.target||event.srcElement;
},
preventDefault:function(event){
if(event.preventDefault){
event.preventDefault;
}else{
event.returnValue = false;
}
},
stopPropagation:function(event){
if(event.stopPropagation){
event.stopPropagation();
}else{
event.cancelBubble = true;
}
}
}
事件类型
UI事件
- load
当页面完全加载后在window上触发,当图像加载完毕时在img元素上触发等
注意:对于新图像元素,只要设置了src属性就会开始下载,但script和link只有在把相关元素添加到文档后才会开始下载
- unload
在文档被完全卸载后触发,利用最多的情况是清除引用,以避免内存泄漏
- resize
当浏览器窗口被调整到一个新的高度或宽度时,就会触发resize事件,建议在该事件的事件处理程序中不要加入大计算量的代码,因为会被频繁执行,从而导致浏览器反应变慢
- scroll事件
发生滚动时触发,虽然在window对象上发生,但它实际表示的是页面中相应元素的变化,通常配合scrollLeft和scrollTop来使用
焦点事件
- focus
- blur
鼠标与滚轮事件
鼠标事件
- click
- dblclick
- mousedown
- mouseup
- mouseenter 在鼠标从元素外部首次移动到元素范围之内触发
- mouseleave 在位于元素上方的鼠标光标移动到元素范围之外时触发
- mousemove 当鼠标指针在元素内部移动时重复地触发
- mouseout 当鼠标指针位于一个元素上方,然后用户将其移入另一个元素时触发,又移入的另一个元素可能位于前一个元素的外部,也可能是这个元素的子元素
- mouseover 在鼠标指针位于一个元素外部,然后用户将其首次移入另一个元素边界之内触发
- mousewheel 当用户通过鼠标滚轮与页面交互、在垂直方向上滚动页面都会触发mousewheel事件
注意 除了mouseenter和mouseleave之外,所有鼠标事件都会冒泡
鼠标事件event特有属性
- 客户区坐标位置:
通过event.clientX和event.clientY来获取鼠标光标距离视口的位置- 页面坐标位置:
通过event.pageX和event.pageY来获取鼠标光标距离页面的位置- 屏幕坐标位置
通过event.screenX和event.screenY来获取鼠标光标距离屏幕的位置- 修改键
鼠标可能会配合修改键使用,可以通过event.shiftKey,event.ctrlKey,event.altKey,event.metaKey的布尔值来获知对应的修改键是否按下了,从而给予正确的反馈事件- 相关元素
在发生mouseover和mouseout事件时,会涉及到更多的元素
①mouseover: 主目标是获得光标的元素,相关元素是失去光标的元素
②mouseout: 主目标是失去光标的元素,相关元素是获得光标的元素
DOM中,event.relatedTarget表示相关元素
IE8之前,前者用event.fromElement,后者用event.toElement来表示相关元素- 鼠标按钮
对于mousedown和mouseup事件,其event对象存在一个button属性,表示按下或释放的按钮,在DOM中,button属性有以下值
0表示主鼠标按钮
1表示中间按钮
2表示次鼠标按钮
在IE8及之前版本中也提供button属性,不过属性值与DOM有很大差异
这里有跨浏览器方案:
var EventUtil = {
//省略了其他代码
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;
}
}
},
//省略了其他代码
};
鼠标滚轮事件
mousewheel的event对象除包含鼠标事件的所有标准信息外,还包含一个特殊的wheelDelta属性(IE,Opera,Chrome,Safari), detail属性(Firefox)
在wheelDelta
向前滚动:wheelDelta是120的倍数
向后滚动:wheelDelta是-120的倍数
在detail
向前滚动:detail的值是3的倍数
前后滚动:detail的值是-3的倍数
此处有跨浏览器方案:
var EventUtil = { //省略了其他代码 getWheelDelta:function(event){ if(event.wheelDelta){ return(client.engine.opera&&client.engine.opera < 9.5 ? -event.wheelDelta : event.wheelDelta); }else{ return -event.detail * 40; } } }
键盘与文本事件
有三个键盘事件和一个文本事件
- keydown: 当用户按下键盘上任意键时触发,按住不放则连续触发
- keypress: 当用户按下键盘上字符键时触发,按住不放则连续触发
(Safari3.1之前的版本在按下非字符键时也会触发 - keyup: 当用户释放键盘上的键时触发
- textInput: 在文本插入文本框前会触发textInput事件,用意是将文本显示给用户之前更容易拦截文本
键盘事件event特有属性
- 键码
在发生keydown和keyup事件时,event对象的keyCode属性会包含一个代码与对应的按键对应- 字符编码
发生keypress事件意味着按下的键会影响到屏幕中文本的显示,因此在所有浏览器中,按下能够插入或删除字符的键都会触发keypress事件
变动事件
- DOMSubtreeModified:在DOM结构中发生任何变化时触发
- DOMNodeInserted:在一个节点作为子节点被插入另一个节点时触发
- DOMNodeRemoved: 在节点从其父节点中被移除时触发
- DOMNodeInsertedIntoDocument:在一个节点被直接插入文档或通过子树间插入文档之后触发
- DOMNodeRedmovedFromDocument:同理
- DOMAttrModified:在特征被修改之后触发
- DOMCharacterDataModified:在文本节点的值发生变化时触发
HTML5事件
- contextmenu:单机鼠标右击事件
- beforeunload:在浏览器卸载页面之前触发
- DOMContentLoaded:在页面中的一切都加载完毕时触发,在形成完整的DOM树之后就会触发,不理会图像、js文件等资源是否下载完毕
- readystatechange
这个事件的目的时提供与文档或元素的加载状态有关的信息,支持此事件的每个对象都有一个readyState属性 - pageshow和pagehide事件(Firfox opera)
- hashchange:在URL的参数列表发生改变时触发
设备事件(略)
触摸与手势事件
触摸事件
- touchstart:当手指触摸屏幕时触发
- touchumove:当手指在屏幕上滑动时连续地触发
- touchend:当手指从屏幕上移开时触发
- touchcancel:当系统停止跟踪触摸时触发
除了常见的DOM属性外,触摸事件还包含下列三个用于跟踪触摸的属性:
(1)touches:表示当前跟踪的触摸操作的Touch对象的数组
(2)targetTouchs:特定与事件目标的Touch对象的数组
(3)changeTouched:表示自上次触摸以来发生了什么变化的Touch对象的数组
手势事件
- gesturestart:当一个手指已经按在屏幕上而另一个手指又触摸屏幕时触发
- gesturechange:当触摸屏幕的任何一个手指的位置发生变化时触发
- gestureend:但任何一个手指从屏幕上面移开时触发。
注意:在一个元素上设置事件处理程序,意味着两个手指必须同时位于该元素的范围之内,才能触发手势事件(这个元素就是目标),由于这些事件冒泡,所以将事件处理程序放在文档上也可以处理所有手势事件,此时事件的目标就是两个手指都位于其范围 内的那个元素。
特殊属性: - rotation:表示手指变化引起的旋转角度,负值表示逆时针旋转
- scale:表示两个手指尖距离的变化情况,这个值从1开始,并随距离拉大而增长,随距离缩小而减小
内存和性能
事件委托
事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件
EventUtil.addHandler(document,'click',function(event){
event = EventUtil.getTarget(event);
switch(target.id){
case "dosomething":
handleDosomething()
break;
case "goSomewhere":
handleGosomgwhere()
break;
}
});
事件委托的优点:
- document对象很快就可以访问,而且在页面生命周期的任何时点上为它添加事件处理程序。换句话说,只要可点击的元素呈现在页面上,就可以立刻具备适当的功能。
- 在页面中设置事件处理程序所需的时间更少,只添加一个事件处理程序所需的DOM引用更少,所花的时间也更少。
- 整个页面占用的内存空间更少,能够提升整体性能
模拟事件
DOM中的事件模拟
- ①document.createEvent()创建一个event对象,可接受一个参数,表示要创建的事件类型的字符串(UIEvetnts,MouseEvents,MutationEvents,HTMLEvents)
- ②创建的event对象都对应有一个特殊的初始化方法,传入适当的数据可以初始化该evnet对象
- ③在DOM节点上使用dispatchEvent()方法触发这个事件
自定义事件
自定义事件不是由DOM原生触发的额,它的目的是让开发人员创建自己的事件。
- ①调用document.createEvent('CustomEvent')创建一个自定义事件对象,有一个名为initCustomEvent()的方法接收以下4个参数:
- type(字符串):触发的事件类型
- bubbles(布尔值):表示时间是否应该冒泡
- cancelable(布尔值):表示事件是否可以取消
- detaitl(对象):任意值,保存在event对象的detail属性中
- ②在对应节点上绑定该事件
- ③使用dispatchEvent(event)事件触发。
此处跳过对IE的事件模拟。