事件处理程序
简介
js和html之间的交互是通过事件实现的,所谓事件就是文档或浏览器窗口中发生的一些特定的交互瞬间。对于事件的处理,浏览器存在差异,主要是IE的兼容性问题,所以大部分都是兼容的,封装成一个事件库,方便调用。
1、事件流
事件流描述的是从页面接收事件的顺序,分为事件冒泡流和事件捕获流
事件冒泡:IE浏览器的事件流,开始由最具体的元素接收,然后逐级向上传播到不那么具体的节点上
事件捕获:Netscape提出的,开始由不那么具体的节点,然后逐级向下传播到最具体的元素接收;在事件到达之前捕获它(老浏览器不支持,建议用事件冒泡)
DOM事件流:DOM2规定事件流包括事件捕获,处于目标阶段和事件冒泡
2、事件处理程序
响应某个事件的函数就是事件处理程序
2.1HTML事件处理程序
<div class="div" title="div box" onclick="changeColor()" onmouseover="alert(this.title)"></div>
function changeColor(){
alert("变颜色")
}
这种就为html事件处理程序
优点:拓展作用域,可以无需引用元素就可以访问元素属性
缺点:时差问题,事件函数不一致,一般onclick="try{showMessage()}catch(ex){}";html和js过于耦合,一般不采取
给相应的属性值设置为null,也可以删除了事件处理程序
2.2DOM0级事件处理程序
<div id="div" title="div box"></div>
div=document.getELementById("div")
div.onclick=function(){
alert("DOM0级事件处理程序")
alert(this.title) 事件处理程序就是在元素的作用域下进行的,可以用this
}
div.onclick=null 删除事件处理程序(通用)
2.3DOM2级事件处理程序
DOM定义事件处理程序有两种方法:
addEventListener(),removeEventListener(),接受三个参数,处理的事件名、事件函数、布尔值(true为捕获,false为冒泡,默认为false)
var div=document.getElementById("div")
div.addEventListener("click",function(){alert("DOM2级事件处理程序")},false)
div.addEventListener("click",function(){alert("可以添加几个事件处理程序,顺序执行")},false)
当removeEventListener时候,中间事件函数必须为函数表达式,不能为匿名函数
div.addEventListener("click",handler,false)
var handler=function(){
alert("函数表达式形式")
}
div.removeEventListener("click",handler,false) 这里可以删除事件处理程序
补充
addEventListener的第三个参数
1 默认为false即冒泡事件,在都不添加的情况下为冒泡
2 一旦有设置为true的,则true先触发
3 在没有子节点的时候,即单一触发,则谁先谁触发
<label>Click me <input type="text"></label> <script> document.querySelector('label').addEventListener('click',function () { console.log(1) }) document.querySelector('input').addEventListener('click',function () { console.log(2) }) </script>
了解label和input间的绑定关系即可知道,每点击label的时候,也会点击input,那么在这种情况下,会弹出1 2 1 第一则为label自己,而2 1 则是冒泡事件
2.4IE事件处理程序
与DOM2级相似为attachEvent()和detachEven(),接受两个参数,处理事件名(这里是带on的),事件函数
var div=document.getELementById("div")
div.attachEvent("onclick",function(){alert("IE浏览器")}) 这里的和DOM0级的区别在于作用域,DOM0级为该元素内,而IE为整个window,this为window,后面的event对象为window.event
div.attachEvent("onclick",function(){alert("多个事件则以相反顺序执行")})
detachEvent和DOM2级一样的
2.5跨浏览器兼容
var EventUtil={
//添加事件处理程序 addHandler:function(element,type,handler){ //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 } } }
3、事件对象
当触发DOM事件时,就会产生一个事件对象event,包含着所有与事件有关的信息,包括导致事件的元素、事件的类型、以及其他与特定事件相关的信息,浏览器支持event,但方式不一,event对象常见的属性和方法
DOM中
type为事件类型
target为事件目标
currentTarget正在处理事件的元素,即谁在处理事件程序就是谁,为this,而target则是总是在实际触发事件的元素上的。
preventDefault()取消事件默认行为,比如a标签本身的跳转
stopPropagation()取消事件的进一步捕获或冒泡
IE中
type为事件类型
srcElement为事件目标
returnValue设置为false取消事件默认行为
cancelBubble设置为true取消事件冒泡
直接上兼容版的
var EventUtil={ //兼容event对象(关键) getEvent:function(event){ return event?event:window.event; }, //获得目标 getTarget:function(event){ return event.target||event.srcElement; }, //取消默认行为 previousDefault:function(event){ if(event.previousDefault){ event.previousDefault(); } else{ event.returnValue=false; } }, //取消事件冒泡 stopPropagation:function(event){ if(event.stopPropagation){ event.stopPropagation(); } else{ event.cancelBubble=true; } }, }
4事件类型
4.1UI事件
load事件
当页面完全加载后在window触发;当img加载后在img上触发;一般用js指定事件处理程序,当然在html内body也可以的,
EventUtil.addHandler(window,"load",function(){ var image=document.createElement("img") document.body.appendChild(image) image.src="console.png" EventUtil.addHandler(image,"load",function(event){ event=EventUtil.getEvent(event) alert(EventUtil.getTarget(event).src) //在图像完全加载后获得信息 }) })
unload事件
当页面完全卸载后触发,从一个页面跳转到另一个页面就会触发unload事件,一般利用其清楚引用,以免避免内存泄露。
resize事件
当改变窗口大小就会触发,以1px为单位
scroll事件
当页面滚动时发生,单位因各个浏览器不同,scrollTop和scrollLeft的兼容性问题
4.2焦点事件
焦点事件会在页面元素获得失去焦点时触发,与document.hasFocus(),document.activeElement属性配合,知道用户在页面的行踪
blur失去焦点时触发,不会冒泡
focus获得焦点时触发,不会冒泡
focusout失去焦点时触发,会冒泡
focusin获得焦点时触发,会冒泡
4.3鼠标事件
客户区坐标位置
EventUtil.addHandler(window,"load",function(event){ EventUtil.addHandler(window,"click",function(event){ event=EventUtil.getEvent(event) alert(event.clientX+","+event.clientY) }) })
总是相对于整个可视区范围的
页面坐标位置
EventUtil.addHandler(window,"click",function(event){ event=EventUtil.getEvent(event) console.log(event.pageX+","+event.pageY) }) 两个效果一样的,page事实上为scrollTop和clientY的和,下面这种兼容性可以的 EventUtil.addHandler(window,"click",function(event){ var event=EventUtil.getEvent(event) var scrollTop=Math.ceil(document.documentElement.scrollTop||document.body.scrollTop) alert(event.clientX+","+(event.clientY+scrollTop)) })
修改键
键盘上的某些键也可以达到鼠标键的效果,DOM中常见的有shiftKey,ctryKey,altKey,metaKey(window or cmd),都是布尔值。
EventUtil.addHandler(another,"click",function(event){ event=EventUtil.getEvent(event) var key=[] if(event.ctrlKey){ key.push("ctrlKey") } if(event.shiftKey){ key.push("shiftKey") } if(event.altKey){ key.push("altKey") } if(event.metaKey){ key.push("metaKey") } console.log(key.join(",")) })
屏幕坐标位置
EventUtil.addHandler(window,"click",function(event){ event=EventUtil.getEvent(event) console.log(event.screenX+","+event.screenY) })
相关元素
一般对于mouseover和mouseout,其他的事件为null,当从原来的元素转移到另一元素,另一元素即为相关元素
getRelatedTarget:function(event){ if(event.relatedTarget){ return event.relatedTarget; } else if(event.toElement){ 兼容IE8版本 return event.toElement } else if(event.formElement){ return event.formElement } else{ return null } },
鼠标按钮
getButton:function(event){ if(document.implementation.hasFeature("MouseEvent","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事件(火狐为DOMMouseScroll),event对象属性wheelDelta,可以得到滚轮的增量值,IE为正负120,Chrome为正负150,火狐为正负120
//鼠标滚轮事件mousewheel getWheelDelta:function(event){ if(event.wheelDelta){ return (client.engine.opear&&client.engine.opear<9.5?-event.wheelDelta:event.wheelDelta); } else{ return -event.detail*40; } }, var client=function(){ //声明浏览器引擎问题 var engine={ //呈现引擎 ie:0, gecko:0, webkit:0, khtml:0, opera:0, //具体版本号 ver:null }; return{ engine:engine }; }();
(function(){ //这里的函数是个私有作用域,不会让其干预到全局作用域 function handlerMouseWheel(event){ event=EventUtil.getEvent(event); var delta=EventUtil.getWheelDelta(event) console.log(delta); } EventUtil.addHandler(window,"mousewheel",handlerMouseWheel); //其他浏览器 EventUtil.addHandler(window,"DOMMouseScroll",handlerMouseWheel); //火狐浏览器 })()
4.4键盘和文本事件
键盘事件主要有三个keydown任意键,keypress字符键,keyup释放键,这三个在输入文本时常用;文本事件为textInput,在文本输入文本框中才触发。
键码:发生键盘事件时,event对象中keyCode属性进行判断,keyCode属性值和ASCII相对应,
常用的keyCode为
空格键32 tab键9 enter键13 shift键16 Ctrl键17 alt键18 backspace键8 方向键37,38,39,40
字符编码:按下能够插入或删除字符的键才触发charCode属性,只有发生keypress时才包含,表示其的ASCII编码,
//字符编码 getCharCode:function(event){ if(typeof event.charCode=="number"){ return event.charCode; } else{ return event.keyCode; } }, EventUtil.addHandler(text1,"keypress",function(event){ event=EventUtil.getEvent(event) console.log(EventUtil.getCharCode(event)) })
4.5HTML5事件
contextmenu事件
单击右键触发上下文事件,将原来的默认事件取消,contextmenu事件是冒泡的,所以用可以用document处理页面所有此类事件
#move{
width:200px;
height:400px;
background:pink;
position:absolute;
display:none;
}
var move=document.getElementById("move")
EventUtil.addHandler(document,"contextmenu",function(event){ event=EventUtil.getEvent(event) EventUtil.previousDefault(event) move.style.left=event.clientX+"px" move.style.top=event.clientY+"px" move.style.display="block" EventUtil.addHandler(document,"click",function(event){ move.style.display="none" }) })
beforeunload事件
当页面卸载前阻止这一操作(比如刷新),将控制权交给用户,是否卸载此页面,提醒作用
EventUtil.addHandler(window,"beforeunload",function(event){ event=EventUtil.getEvent(event) EventUtil.previousDefault(event) var message="really to leave" })
DOMContentLoaded事件
此事件在load事件之前发生,不会因为加载外部的css或者js等文件资源而延迟,使得用户更早的交互,对于不支持此事件比如IE8,9等,可以采用定时器的方法
setTimeout(function(){alert("breforeload"),0}) 对于不支持的采取这种,但是也不可以保证
EventUtil.addHandler(window,"load",function(){ alert("load") }) EventUtil.addHandler(document,"DOMContentLoaded",function(event){ alert("beforeload") })
readystatechange事件:提供与文档或元素加载状况的信息
pageshow和pagehide事件
往返缓存(bfcache),可以在用户使用浏览器后退或前进按钮加载页面的转换速度,不仅保存页面数据,还保存DOM,js状态,将整个页面保存在内存中。
pageshow事件。在页面显示时触发,无论是否来自bfcache,虽然是在document触发的,但是必须在window上进行事件程序员处理
function change(){ var count=0 EventUtil.addHandler(window,"load",function(){ alert("load") }) EventUtil.addHandler(window,"pageshow",function(event){ count++ alert(event.persisted) //判断页面是否保存在往返缓存中,布尔值 }) EventUtil.addHandler(window,"pagehide",function(event){ alert(event.persisted) //当卸载页面时触发 }) } change()
hashchange事件
在URL的参数列表发生变化时通知,在Ajax应用中,利用URL参数列表保存状态或导航信息;此时Event有oldURL和newURL属性分别保存前后完整的参数列表的URL,不过兼容浏览器直接用location判断。
EventUtil.addHandler(window,"hashchange",function(event){ alert(locationn.hash) //使用location对象确定当前的参数列表 })
4.6设备事件暂时不考虑,等涉及到移动端再好好补充
5内存和性能
5.1事件委托
所谓事件委托就是利用事件冒泡,只给指定一个事件处理程序,就可以管理某一类型的所有事件,解决的就是事件处理程序太多的问题,以此提高性能;适合采用这种方法的有click,mousedown,keydown,keyup,keypress
EventUtil.addHandler(list,"click",function(event){ 只需要在一个ul上添加事件,然后通过target来实现行为,这也就是target和currentTarget之间的区别,好处多多 event=EventUtil.getEvent(event) var target=EventUtil.getTarget(event) switch(target.id){ //利用条件判断 case "baidu": target.style.color="red" target.style.cursor="pointer" document.title="i have change" break; case "ali": location.href="http://www.baidu.com" break; case "tengxun": alert("Tencent") break; } })
5.2移除事件程序
当不需要事件时,需要将已有的事件处理程序移除即那些过时不用的空事件处理程序(dangling event handler),比如innerHTML代替原来的东西,原来的事件必须移除以此提高性能。当已知的元素即将移除,最好手工移除事件比如下面。
var btn=document.getElementById("btn") btn.onclick=function(){ alert("事件发生后,我就不再需要了") btn.onclick=null }
模拟事件暂时不需要,以后再细细道来