摘要:學習要點傳統(tǒng)事件綁定的問題事件處理函數事件處理函數事件對象的其他補充事件綁定分為兩種一種是傳統(tǒng)事件綁定內聯(lián)模型,腳本模型,一種是現(xiàn)代事件綁定級模型?,F(xiàn)代事件綁定在傳統(tǒng)綁定上提供了更強大更方便的功能。事件和事件事件和事件,有關加載方面的事件。
學習要點:
1.傳統(tǒng)事件綁定的問題
2.W3C事件處理函數
3.IE事件處理函數
4.事件對象的其他補充
事件綁定分為兩種:一種是傳統(tǒng)事件綁定(內聯(lián)模型,腳本模型),一種是現(xiàn)代事件綁定(DOM2級模型)?,F(xiàn)代事件綁定在傳統(tǒng)綁定上提供了更強大更方便的功能。
一 傳統(tǒng)事件綁定的問題傳統(tǒng)事件綁定中的內聯(lián)模型不做討論,基本很少去用。先來看一下腳本模型,腳本模型將一個函數賦值給一個事件處理函數。傳統(tǒng)綁定如:
window.onload=function(){ var box=document.getElementById("box"); box.onclick = function(){ alert("Lee"); }; };
問題一:一個事件處理函數觸發(fā)兩次事件
如果一個頁面有兩個或者多個js,并且第一個js是第一個程序開發(fā)的,第二個js是第二個程序員開發(fā)的。第一個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()不能執(zhí)行的 //所以saved()相當于window.onload=function(){} window.onload=function(){ if(saved){ saved();//執(zhí)行上一個事件 window.onload=function(){} } alert("Mr.lee"); //執(zhí)行本事件 }
問題二:事件切換器
切換一個id為box的div,讓里面的背景red與blue直接切換,并且切換之前彈框一次,如:
window.onload=function(){ var box=document.getElementById("box"); box.className="red"; box.onclick=function(){ alert("Lee"); //只執(zhí)行了一次 blue.call(this);//通過匿名函數執(zhí)行某一函數,那么里面的this就是代表的window,所以可以通過call傳遞 }; } function blue(){ this.className="blue"; this.onclick=red; } function red(){ this.className="red"; this.onclick=blue; }
上面的代碼雖然實現(xiàn)了切換功能,但是彈框只執(zhí)行了一次。
//添加事件函數 //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(){ //目的達到,每次都執(zhí)行了,沒有被覆蓋 // 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,太多的遞歸 //因為積累了太多的保存的事件 //解決方案,就是用完的事件,就立刻移除掉
按照上面的代碼出現(xiàn)了注釋中的錯誤,解決的辦法如下:
//添加事件函數 //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(){ //目的達到,每次都執(zhí)行了,沒有被覆蓋 // 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.添加一個額外的方法,會不會被覆蓋,或者只能執(zhí)行一次,解決
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值,用來設置事件是在事件捕獲時執(zhí)行,還是事件冒泡時執(zhí)行。而不兼容W3C的瀏覽器(IE)用attachEvent()方法,此方法沒有相關設置,不過IE的事件模型默認是在事件冒泡時執(zhí)行的,也就是在useCapture等于false的時候執(zhí)行,所以把在處理事件時把useCapture設置為false是比較安全,也實現(xiàn)兼容瀏覽器的效果。
事件捕獲階段:事件從最上一級標簽開始往下查找,直到捕獲到事件目標(target)。
事件冒泡階段:事件從事件目標(target)開始,往上冒泡直到頁面的最上一級標簽。
事件的傳播是可以阻止的:
在W3c中,使用stopPropagation()方法
在IE下設置cancelBubble = true;
IE實現(xiàn)了與DOM中類似的兩個方法:attachEvent()和detachEvent()。這兩個方法接受相同的參數:事件名稱和函數。
在使用這兩組函數的時候,先把區(qū)別說一下:1.IE不支持捕獲,只支持冒泡;2.IE添加事件不能屏蔽重復的函數;3.IE中的this指向的是window而不是DOM對象。4.在傳統(tǒng)事件上,IE是無法接受到event對象的,但使用了attchEvent卻可以,但有些區(qū)別。
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.添加一個額外的方法,會不會被覆蓋,或者只能執(zhí)行一次,解決。
在傳統(tǒng)綁定上,IE是無法像W3C那樣通過傳參接受event對象,但是使用attachEvent()卻可以。
window.attachEvent("onload",function(){ var box=document.getElementById("box"); box.onclick=function(evt){ //傳統(tǒng)方法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; } }屏蔽跳轉操作
取消事件的默認行為有一種不規(guī)范的做法,就是返回false。
link.onclick=function(){ alert("Lee"); return false; }
PS:雖然return false;可以實現(xiàn)這個功能,但是有漏洞。
第一:必須寫到最后,這樣導致中獎的代碼執(zhí)行后,有可能執(zhí)行不到return false;
第二:return false 寫到最前那么之后的自定義操作就失效了。
所以最好的辦法應該是在最前面就阻止默認行為,并且后面的代碼還可以執(zhí)行。
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事件很常用,這直接導致瀏覽器兼容性較為穩(wěn)定。
卸載前事件: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:通過瀏覽器檢測可以確定火狐只執(zhí)行DOMMouseScroll。
DOMContentLoaded事件和readystatechange事件DOMContentLoaded事件和readystatechange事件,有關DOM加載方面的事件。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://systransis.cn/yun/78841.html
摘要:模塊化是隨著前端技術的發(fā)展,前端代碼爆炸式增長后,工程化所采取的必然措施。目前模塊化的思想分為和。特別指出,事件不等同于異步,回調也不等同于異步。將會討論安全的類型檢測惰性載入函數凍結對象定時器等話題。 Vue.js 前后端同構方案之準備篇——代碼優(yōu)化 目前 Vue.js 的火爆不亞于當初的 React,本人對寫代碼有潔癖,代碼也是藝術。此篇是準備篇,工欲善其事,必先利其器。我們先在代...
摘要:忍者級別的函數操作對于什么是匿名函數,這里就不做過多介紹了。我們需要知道的是,對于而言,匿名函數是一個很重要且具有邏輯性的特性。通常,匿名函數的使用情況是創(chuàng)建一個供以后使用的函數。 JS 中的遞歸 遞歸, 遞歸基礎, 斐波那契數列, 使用遞歸方式深拷貝, 自定義事件添加 這一次,徹底弄懂 JavaScript 執(zhí)行機制 本文的目的就是要保證你徹底弄懂javascript的執(zhí)行機制,如果...
閱讀 2186·2023-04-26 00:23
閱讀 861·2021-09-08 09:45
閱讀 2472·2019-08-28 18:20
閱讀 2597·2019-08-26 13:51
閱讀 1629·2019-08-26 10:32
閱讀 1426·2019-08-26 10:24
閱讀 2058·2019-08-26 10:23
閱讀 2230·2019-08-23 18:10