标题 | javascript事件绑定学习要点 |
内容 | 这篇文章主要介绍了javascript事件绑定学习要点,主要包含下面四个方面1.传统事件绑定的问题,2.W3C事件处理函数,3.IE事件处理函数,4.事件对象的其他补充,有需要的小伙伴可以参考下 事件绑定分为两种:一种是传统事件绑定(内联模型,脚本模型),一种是现代事件绑定(DOM2级模型)。现代事件绑定在传统绑定上提供了更强大更方便的功能。 一 传统事件绑定的问题 传统事件绑定中的内联模型不做讨论,基本很少去用。先来看一下脚本模型,脚本模型将一个函数赋值给一个事件处理函数。传统绑定如: window.onload=function(){ var box=document.getElementById('box'); box.onclick = function(){ alert('Lee'); }; }; 问题一:一个事件处理函数触发两次事件 如果一个页面有两个或者多个js,并且第一个js是第一个程序开发的,第二个js是第二个程序员开发的。第一个window.onload被覆盖了,如 window.onload=function(){ alert('Lee'); }; window.onload=function(){ alert('Mr.lee'); } 结果只是打印了 Mr.lee 其实是有办法解决这个问题的,看下面这两种形式。 a: alert(window.onload);//一开始没有注册window.onload,那么就是null window.onload=function(){ alert('Lee'); }; alert(window.onload);//如果已经有window.onload,打印的是函数function window.onload=function(){ alert('Mr.lee'); } b: alert(typeof window.onload);//一开始没有window.onolad,旧版火狐显示undefined,新版显示object, window.onload=function(){ alert('Lee'); }; alert(typeof window.onload);//如果已经有window.onload,所有浏览器都会显示function window.onload=function(){ alert('Mr.lee'); } 所以解决办法有了。 window.onload=function(){ alert('Lee'); }; if(typeof window.onload=='function'){ var saved=null;//保存上一个事件对象 saved=window.onload; } //saved 就是window.onload,saved()相当于window.onload(),但是window.onload()不能执行的 //所以saved()相当于window.onload=function(){} window.onload=function(){ if(saved){ saved();//执行上一个事件 window.onload=function(){} } alert('Mr.lee'); //执行本事件 } 问题二:事件切换器 切换一个id为box的div,让里面的背景red与blue直接切换,并且切换之前弹框一次,如: window.onload=function(){ var box=document.getElementById('box'); box.className="red"; box.onclick=function(){ alert('Lee'); //只执行了一次 blue.call(this);//通过匿名函数执行某一函数,那么里面的this就是代表的window,所以可以通过call传递 }; } function blue(){ this.className="blue"; this.onclick=red; } function red(){ this.className="red"; this.onclick=blue; } 上面的代码虽然实现了切换功能,但是弹框只执行了一次。 //添加事件函数 //obj相当于window //type相当于onload //fn相当于function(){} function addEvent(obj,type,fn){ //用于保存上一个事件 var saved=null; if(typeof obj['on'+type]=='function'){ saved=obj['on'+type];//保存上一个事件 } obj['on'+type]=function(){ if(saved){ saved(); } fn.call(this); } } addEvent(window,'load',function(){ var box=document.getElementById("box"); //addEvent(box,'click',function(){ //目的达到,每次都执行了,没有被覆盖 // alert('ss'); //}); addEvent(box,'click',blue); }); function red(){ this.className="red"; addEvent(box,'click',blue); } function blue(){ this.className="blue"; addEvent(box,'click',red); } //当不停的切换的时候,浏览器突然卡死,并且报错:too much recursion,太多的递归 //因为积累了太多的保存的事件 //解决方案,就是用完的事件,就立刻移除掉 按照上面的代码出现了注释中的错误,解决的办法如下: //添加事件函数 //obj相当于window //type相当于onload //fn相当于function(){} function addEvent(obj,type,fn){ //用于保存上一个事件 var saved=null; if(typeof obj['on'+type]=='function'){ saved=obj['on'+type];//保存上一个事件 } obj['on'+type]=function(){ if(saved){ saved(); } fn.call(this); } } //当不停的切换的时候,浏览器突然卡死,并且报错:too much recursion,太多的递归 //因为积累了太多的保存的事件 //解决方案,就是用完的事件,就立刻移除掉 //移除事件函数 function removeEvent(obj,type){ if(obj['on'+type]){ obj['on'+type]=null; } } addEvent(window,'load',function(){ var box=document.getElementById("box"); //addEvent(box,'click',function(){ //目的达到,每次都执行了,没有被覆盖 // alert('ss'); //}); addEvent(box,'click',blue); }); function red(){ this.className="red"; removeEvent(this,'click'); addEvent(box,'click',blue); } function blue(){ this.className="blue"; removeEvent(this,'click'); addEvent(box,'click',red); } 二 W3C事件处理函数 addEventListener()与removeEventListener() W3C事件处理函数两个,addEventListener()与removeEventListener()。 //W3C自带的两个添加事件和删除事件 1.覆盖问题,解决 window.addEventListener('load',function(){ alert('Lee'); },false); window.addEventListener('load',function(){ alert('Mr.Lee'); },false); window.addEventListener('load',function(){ alert('Mrs.Lee'); },false); 2.相同函数屏蔽的问题,解决 window.addEventListener('load',init,false); window.addEventListener('load',init,false); window.addEventListener('load',init,false); function init(){ alert('Lee'); } 3.是否可以传递this,解决 例子1: window.addEventListener('load',function(){ var box=document.getElementById('box'); box.addEventListener('click',function(){ alert(this); },false); },false); 例子2: window.addEventListener('load',function(){ var box=document.getElementById('box'); box.addEventListener('click',blue,false); },false); function red(){ this.className="red"; this.removeEventListener('click',red,false); this.addEventListener('click',blue,false); } function blue(){ this.className="blue"; this.removeEventListener('click',blue,false); this.addEventListener('click',red,false); } 4.添加一个额外的方法,会不会被覆盖,或者只能执行一次,解决 window.addEventListener('load',function(){ var box=document.getElementById('box'); box.addEventListener('click',function(){ alert('Lee'); },false); box.addEventListener('click',blue,false); },false); 综上所述:W3C是比较完美的解决了这些问题,非常好用,但是IE8和之前的浏览器并不支持,而是采用了自己的事件,当然IE9已经完全支持了W3C的这两个事件处理函数。 W3C可以设置冒泡和捕获方式。 支持W3C标准的浏览器在添加事件时用addEventListener(event,fn,useCapture)方法,基中第3个参数useCapture是一个Boolean值,用来设置事件是在事件捕获时执行,还是事件冒泡时执行。而不兼容W3C的浏览器(IE)用attachEvent()方法,此方法没有相关设置,不过IE的事件模型默认是在事件冒泡时执行的,也就是在useCapture等于false的时候执行,所以把在处理事件时把useCapture设置为false是比较安全,也实现兼容浏览器的效果。 事件捕获阶段:事件从最上一级标签开始往下查找,直到捕获到事件目标(target)。 事件冒泡阶段:事件从事件目标(target)开始,往上冒泡直到页面的最上一级标签。 事件的传播是可以阻止的: 在W3c中,使用stopPropagation()方法 在IE下设置cancelBubble = true; 三.IE事件处理函数 attachEvent()和detachEvent() IE实现了与DOM中类似的两个方法:attachEvent()和detachEvent()。这两个方法接受相同的参数:事件名称和函数。 在使用这两组函数的时候,先把区别说一下:1.IE不支持捕获,只支持冒泡;2.IE添加事件不能屏蔽重复的函数;3.IE中的this指向的是window而不是DOM对象。4.在传统事件上,IE是无法接受到event对象的,但使用了attchEvent却可以,但有些区别。 1.覆盖问题,解决了,但有不同,结果是Mrs.Lee,Mr.Lee,最后是Lee window.attachEvent('onload',function(){ alert('Lee'); }); window.attachEvent('onload',function(){ alert('Mr.Lee'); }); window.attachEvent('onload',function(){ alert('Mrs.Lee'); }); 2.相同函数屏蔽的问题,未解决。 window.attachEvent('onload',init); window.attachEvent('onload',init); function init(){ alert('Lee'); } 3.是否可以传递this,不能,this指的是window。需要用call方法。 window.attachEvent('onload',function(){ var box=document.getElementById('box'); box.attachEvent('onclick',function(){ //alert(this===box); alert(this===window); //true }); }); 下面还有办法就是通过window.event.srcElement。代码如下: window.attachEvent('onload',function(){ var box=document.getElementById('box'); box.attachEvent('onclick',blue); }); function red(){ var that=window.event.srcElement; that.className="red"; that.detachEvent('onclick',red); that.attachEvent('onclick',blue); } function blue(){ var that=window.event.srcElement; that.className="blue"; that.detachEvent('onclick',blue); that.attachEvent('onclick',red); } 4.添加一个额外的方法,会不会被覆盖,或者只能执行一次,解决。 在传统绑定上,IE是无法像W3C那样通过传参接受event对象,但是使用attachEvent()却可以。 window.attachEvent('onload',function(){ var box=document.getElementById('box'); box.onclick=function(evt){ //传统方法IE无法通过参数获取evt alert(evt);//undefined } box.attachEvent('onclick',function(evt){ alert(evt);//object alert(evt.type);//click alert(evt.srcElement.tagName);//DIV alert(window.event.srcElement.tagName);//DIV }); }); 跨浏览器的兼容 跨浏览器添加事件 function addEvent(obj,type,fn){ if(obj.addEventListener){ obj.addEventListener(type,fn,false); }else if(obj.attachEvent){ obj.attachEvent('on'+type,fn); } } 跨浏览器移除事件 function removeEvent(obj,type,fn){ if(obj.removeEventListener){ obj.removeEventListener(type,fn,false); }else if(obj.detachEvent){ obj.detachEvent('on'+type,fn); } } 跨浏览器获取目标对象 function getTarget(evt){ if(evt.target){ return evt.target; }else if(window.event.srcElement){ return window.event.srcElement; } } 调用方式: addEvent(window,'load',function(){ var box=document.getElementById('box'); addEvent(box,'click',blue); }); function red(evt){ var that=getTarget(evt); that.className="red"; removeEvent(that,'click',red); addEvent(that,'click',blue); } function blue(evt){ var that=getTarget(evt); that.className="blue"; removeEvent(that,'click',blue); addEvent(that,'click',red); } 四.事件对象的其他补充 relatedTarget事件 w3c中的一个relatedTarget事件。 例如: addEvent(window,'load',function(){ var box=document.getElementById('box'); addEvent(box,'mouseover',function(evt){ alert(evt.relatedTarget); //得到移入box最近的那个DOM对象 }); addEvent(box,'mouseout',function(evt){ alert(evt.relatedTarget); //从box移出最近的那个DOM对象 }); }); IE提供了两组分别用于移入移出的属性fromElement和toElement,分别对应mouseover和mouseout。 addEvent(window,'load',function(){ var box=document.getElementById('box'); addEvent(box,'mouseover',function(){ alert(window.event.fromElement.tagName); //得到移入box最近的那个DOM对象 }); addEvent(box,'mouseout',function(){ alert(window.event.toElement.tagName); //从box移出最近的那个DOM对象 }); }); PS:fromElement和toElement如果分别对应相反的鼠标事件,没有任何意义。 剩下要做的就是跨浏览器兼容操作: function getTarget(evt){ var e=evt || window.event; if(e.srcElment){ //IE if(e.type=='mouseover'){ return e.fromElement.tagName; }else if(e.type="mouseout"){ return e.toElement.tagName; } }else if(e.relatedTarget){ //w3c return e.relatedTarget; } } 屏蔽跳转操作 取消事件的默认行为有一种不规范的做法,就是返回false。 link.onclick=function(){ alert('Lee'); return false; } PS:虽然return false;可以实现这个功能,但是有漏洞。 第一:必须写到最后,这样导致中奖的代码执行后,有可能执行不到return false; 第二:return false 写到最前那么之后的自定义操作就失效了。 所以最好的办法应该是在最前面就阻止默认行为,并且后面的代码还可以执行。 link.onclick=function(evt){ evt.preventDefault;//w3c,阻止默认行为 alert('Lee'); } link.onclick=function(evt){ window.event.returnValue=false;//IE,阻止默认行为 alert('Lee'); } 那么跨浏览器的兼容: function preDef(evt){ var e=evt || window.event; if(e.preventDefault){ e.preventDefault(); }else{ e.returnValue=false; } } 右键菜单contextmenu 兼容: function preDef(evt){ var e=evt || window.event; if(e.preventDefault){ e.preventDefault(); }else{ e.returnValue=false; } } addEvent(window,"load",function(){ var body=document.getElementsByTagName('body')[0]; addEvent(body,'contextmenu',function(evt){ preDef(evt); }) }); PS:contextmenu事件很常用,这直接导致浏览器兼容性较为稳定。 卸载前事件:beforeunload 这个事件可以帮助在离开本页的时候给出相应的提示,“离开”或者“返回”操作。 addEvent(window,'beforeonload',function(){ preDef(evt); }); 鼠标滚轮(mousewheel)和DOMMouseScroll 用于获取鼠标上下滚轮的距离 addEvent(document,'mousewheel',function(evt){ //非火狐 alert(getWD(evt)); }); addEvent(document,'DOMMouseScroll',function(evt){ //火狐 alert(getWD(evt)); }); function getWD(evt){ var e=evt|| window.event; if(e.wheelDelta){ return e.wheelDelta; }else if(e.detail){ //火狐 return -evt.detail*30; } } PS:通过浏览器检测可以确定火狐只执行DOMMouseScroll。 DOMContentLoaded事件和readystatechange事件 DOMContentLoaded事件和readystatechange事件,有关DOM加载方面的事件。 |
随便看 |
|
在线学习网考试资料包含高考、自考、专升本考试、人事考试、公务员考试、大学生村官考试、特岗教师招聘考试、事业单位招聘考试、企业人才招聘、银行招聘、教师招聘、农村信用社招聘、各类资格证书考试等各类考试资料。