// 事件綁定分為兩種: // 一種是傳統(tǒng)事件綁定(內(nèi)聯(lián)模型/腳本模型);上一章內(nèi)容; // 一種是現(xiàn)代事件綁定(DOM2級(jí)模型);現(xiàn)代事件綁定在傳統(tǒng)事件綁定基礎(chǔ)上提供了更強(qiáng)大的功能; 一 傳統(tǒng)事件綁定的問(wèn)題1 // 腳本模型將一個(gè)函數(shù)賦值給一個(gè)事件處理函數(shù); 2 var box = document.getElementById('box'); // 獲取元素; 3 box.onclick = function(){ // 元素點(diǎn)擊觸發(fā)事件; 4 alert('Lee'); 5 } 6 7 // 問(wèn)題一:一個(gè)事件處理函數(shù)觸發(fā)兩次事件; 8 window.onload = function(){ // 第一組程序; 9 alert('Lee'); 10 } 11 window.onload = function(){ // 第二組程序; 12 alert('Mr.Lee'); 13 } 14 // PS:當(dāng)兩組程序同時(shí)執(zhí)行的時(shí)候,后面一個(gè)會(huì)把前面一個(gè)完全覆蓋; 15 // 導(dǎo)致前面的window.onload完全失效了; 16 // 解決方案: 17 window.onload = function(){ // 第一組事件處理程序,會(huì)被覆蓋; 18 alert('Lee'); 19 } 20 if(typeof window.onload == 'function'){ // 判斷之前是否有window.onload; 21 var saved = null; // 創(chuàng)建一個(gè)保存器; 22 saved = window.onload; // 把之前的window.onload保存起來(lái); 23 } 24 window.onload = function(){ // 下一個(gè)要執(zhí)行的事件; 25 // saved()=window.onload = function 26 if(saved)saved(); // 判斷之前是否有事件,如果有則先執(zhí)行之前保存的事件; 27 alert('Mr.Lee'); // 執(zhí)行本事件的代碼; 28 } // 問(wèn)題二:事件切換器 box.onclick = boBlue; // 第一次執(zhí)行toBlue(); function toRed(){ this.className = 'red'; this.onclick = toBlue; // 第三次執(zhí)行roBlue(),然后來(lái)回切換; } function toBlue(){ this.className = 'blue'; this.onclick = toRed; // 第二次執(zhí)行toRed(); } // 這個(gè)切換器在擴(kuò)展的時(shí)候,會(huì)出現(xiàn)一些問(wèn)題: 1.如果增加一個(gè)執(zhí)行函數(shù),那么會(huì)被覆蓋; box.onclick = toAlert; // 被增加的函數(shù); box.onclick = toBlue; // toAlert被覆蓋了; 2.如果解決覆蓋問(wèn)題,就必須包含同時(shí)執(zhí)行; box.onclick = function(){ // 包含進(jìn)去,但可讀性降低; toAlert(); // 第一次不會(huì)被覆蓋,但第二次又被覆蓋; toBlue.call(this); // 還必須把this傳遞到切換器里; } 1 // 綜上三個(gè)問(wèn)題:覆蓋問(wèn)題/可讀性問(wèn)題/this傳遞為題; 2 // 我們創(chuàng)建一個(gè)自定義事件處理函數(shù); 3 function addEvent(obj,type,fn){ // 取代傳統(tǒng)事件處理函數(shù); 4 var saved = null; // 保存每次觸發(fā)的事件處理函數(shù); 5 if(typeof obj['on'+type] == 'function'){// 判斷是不是存在事件; 6 saved = obj['on'+type]; // 如果有,保存起來(lái); 7 } 8 obj['on'+type] = function(){ // 然后執(zhí)行; 9 if(saved)saved(); // 執(zhí)行上一個(gè); 10 fn.call(this); // 執(zhí)行函數(shù),把this傳遞進(jìn)去; 11 } 12 } 13 addEvent(window,'load',function(){ 14 alert('Lee'); // 可以執(zhí)行; 15 }); 16 addEvent(window.'load',function(){ 17 alert('Mr.Lee'); // 可以執(zhí)行; 18 }) 19 20 // 用自定義事件函數(shù)注冊(cè)到切換器上查看效果: 21 addEvent(window,'load',function(){ 22 var box = document.getElementById('box'); 23 addEvent(box,'click',toBlue); 24 }); 25 function toRed(){ 26 this.className = 'red'; 27 addEvent(this,'click',toBlue); 28 } 29 function toBlue(){ 30 this.className = 'blue'; 31 addEvent(this,'click',toRed); 32 二 W3C事件處理函數(shù)// "DOM2級(jí)事件"定義了兩個(gè)方法,用于添加事件和刪除事件的處理程序:addEventListener()和removeEventListener(); 1 // 所有DOM節(jié)點(diǎn)中都包含這兩個(gè)方法,并且它們都接收3個(gè)參數(shù):事件名/函數(shù)/冒泡或捕獲的布爾值(true表示捕獲,false表示冒泡); 2 window.addEventListener('load',function(){ 3 alert('Lee'); 4 },false); 5 window.addEventListener('load',function(){ 6 alert('Mr.Lee'); 7 },false); 8 // PS:W3C的事件綁定好處:1.不需要自定義了;2.可以屏蔽相同的函數(shù);3.可以設(shè)置冒泡和捕獲; 9 window.addEventListener('load',init,false); // 第一次執(zhí)行了; 10 window.addEventListener('load',init,false); // 第二次被屏蔽了; 11 function init(){ 12 alert('Lee'); 13 } 14 15 // 事件切換器 16 window.addEventListener('load',function(){ 17 var box = document.getElementById('box'); 18 box.addEventListener('click',function(){ // 不會(huì)被覆蓋/誤刪; 19 alert('Lee'); 20 },false); 21 box.addEventListener('click',toBlue,false); // 引入切換; 22 },false); 23 24 function toRed(){ 25 this.className = 'red'; 26 this.removeEventListener('click',toRed,false); // 移除事件處理函數(shù); 27 this.addEventListener('click',toBlue,false); // 添加需要切換的事件處理函數(shù); 28 } 29 30 function toBlue(){ 31 this.className = 'blue'; 32 this.removeEventListener('click',toBlue,false); 33 this.addEventListener('click',toRed,false); 34 } 35 36 // 設(shè)置冒泡和捕獲階段 37 document.addEventListener('click',function(){ 38 alert('document'); 39 },true); // 設(shè)置為捕獲; 40 41 document.addEventListener('click',function(){ 42 alert('Lee'); 43 },false); // 設(shè)置為冒泡; 三 IE事件處理函數(shù)// IE中實(shí)現(xiàn)了與DOM中類(lèi)似的兩個(gè)方法:attachEvent()和detachEvent(); // 這兩個(gè)方法接收相同的參數(shù):事件名和函數(shù); 1 // 在使用這兩組函數(shù)的時(shí)候,區(qū)別: 2 // 1.IE不支持捕獲,只支持冒泡; 3 // 2.IE添加事件不能屏蔽重復(fù)的函數(shù); 4 // 3.IE中的this指向的是window而不是DOM對(duì)象; 5 // 4.在傳統(tǒng)事件上,IE是無(wú)法接受到event對(duì)象的;但使用了attachEvent()卻可以; 6 window.attachEvent('onload',function(){ 7 var box = document.getElementById('box'); 8 box.attachEvent('onclick',toBlue); 9 }); 10 11 function toRed(){ 12 var that = window.event.srcElement; 13 that.className = 'red'; 14 that.detachEvent('onclick',toRed); 15 that.attachEvent('onclick',toBlue); 16 } 17 18 function toBlue(){ 19 var that = window.event.srcElement; 20 that.className = 'blue'; 21 that.detachEvent('onclick',toBlue); 22 that.attachEvent('onclick',toRed); 23 } 24 // PS:IE不支持捕獲; 25 // IE不能屏蔽; 26 // IE不能傳遞this,可以call過(guò)去; 27 28 // 在傳統(tǒng)綁定上,IE是無(wú)法像W3C那樣通過(guò)傳參接受event對(duì)象;但如果使用了attachEvent()卻可以; 29 box.onclick = function(evt){ 30 alert(evt); // undefined; 31 } 32 33 box.attachEvent('onclick',function(evt){ 34 alert(evt); // object; 35 alert(evt.type); // click; 36 }); 37 38 // 兼容IE和W3C的事件切換器函數(shù); 39 function addEvent(obj,type,fn){ // 添加事件處理程序兼容; 40 if(obj.addEventListener){ 41 obj.addEventListener(type,fn); 42 }else if(obj.attachEvent){ 43 obj.attachEvent('on'+type,fn); 44 } 45 } 46 47 function removeEvent(obj,type,fn){ // 移除事件處理程序兼容; 48 if(obj.removeEventListener){ 49 obj.removeEventListener(type,fn); 50 }esle if(obj.detachEvent){ 51 obj.detachEvent('on'+type,fn); 52 } 53 } 54 55 function getTarget(evt){ // 得到事件目標(biāo); 56 if(evt.target){ 57 return evt.target; 58 }else if(window.event.srcEleemnt){ 59 return window.event.srcElement; 60 } 61 } 四 事件對(duì)象補(bǔ)充1 1.relatedTarget 2 // 這個(gè)屬性可以在mouseover和mouseout事件中獲取從哪里移入和從哪里移出的DOM對(duì)象; 3 box.onmouseover = function(evt){ // 鼠標(biāo)移入box; 4 alert(evt.relatedTarget); // 獲取移入box之前的那個(gè)元素; 5 } 6 box.onmouseout = function(evt){ // 鼠標(biāo)移出box; 7 alert(evt.relatedTarget); // 獲取移出box之后到的那個(gè)元素; 8 } 9 10 // IE提供了兩組與之對(duì)應(yīng)的屬性:fromElement和toElement; 11 // 兼容函數(shù) 12 function getEarget(evt){ 13 var e = evt || window.event; // 得到事件對(duì)象; 14 if(e.srcElement){ // 如果支持srcElement,表示IE; 15 if(e.type == 'mouseover'){ // 如果是over事件; 16 return e.fromeElement; // 就使用from; 17 }else if(e.type == 'mouseout'){ // 如果是out; 18 return e.toElement; // 就使用to; 19 } 20 }else if(e.relatedTarget){ // 如果支持relatedTarget,表示W(wǎng)3C; 21 return e.relatedTarget; 22 } 23 } 1 2.阻止事件的默認(rèn)行為 2 // 一個(gè)超鏈接的默認(rèn)行為就點(diǎn)擊然后跳轉(zhuǎn)到指定的頁(yè)面; 3 // 那么阻止默認(rèn)行為就可以屏蔽跳轉(zhuǎn)的這種操作,而實(shí)現(xiàn)自定義操作; 4 // 取消事件默認(rèn)行為還有一種不規(guī)范的做法,就是返回false; 5 link.onclick = function(){ 6 alert('Lee'); 7 return false; // 直接返回false,就不會(huì)跳轉(zhuǎn)了; 8 } 9 // PS:雖然return false;可以實(shí)現(xiàn)這個(gè)功能,但有漏洞; 10 // 第一:代碼必須寫(xiě)到最后,這樣導(dǎo)致中間的代碼執(zhí)行后,有可能執(zhí)行不到return false; 11 // 第二:return false寫(xiě)到最前那么之后的自定義操作就失敗了; 12 // 解決方案:在最前面就阻止默認(rèn)行為,并且后面還能執(zhí)行代碼; 13 function preDef(evt){ // 跨瀏覽器兼容阻止默認(rèn)行為; 14 var e = evt || window.event; 15 if(e.preventDefault){ 16 e.preventDefault(); // W3C,阻止默認(rèn)行為; 17 }else{ 18 e.returnValue = false; // IE,阻止默認(rèn)行為; 19 } 20 } 1 3.上下文菜單事件contextmenu 2 // 當(dāng)我們右擊網(wǎng)頁(yè)的時(shí)候,會(huì)自動(dòng)出現(xiàn)windows自帶的菜單; 3 // 那么我們可以使用contextmenu事件來(lái)修改我們指定的菜單;但前提是把右擊的默認(rèn)行為取消; 4 addEvent(window,'load',function(){ 5 var text = docuemnt.getElementById('text'); 6 addEvent(text,'contextmenu',function(evt){ // 添加右鍵菜單事件處理程序; 7 var e = evt || window.event; 8 preDef(e); // 阻止默認(rèn)行為函數(shù); 9 var menu = document.getElementById('menu'); // 找到自定義的menu對(duì)象; 10 menu.style.left = e.clientX+'px'; // 確定自定義menu在屏幕上的位置; 11 menu.style.top = e.clientX+'px'; 12 menu.style.visibility = 'visible'; // 設(shè)置自定義menu的屬性為可見(jiàn); 13 addEvent(document,'click',function(){ // 給document添加單擊事件處理程序; 14 docuemnt.getElementById('myMenu').style.visibility = 'hidden'; //將自定義的menu隱藏; 15 }); 16 }); 17 }); 1 4.卸載前事件beforeunload 2 // 這個(gè)事件可以幫助在離開(kāi)本頁(yè)的時(shí)候給出相應(yīng)的提示;"離開(kāi)"或"返回"操作; 3 addEvent(window.'beforeunload',function(evt){ 4 var evt = event || window.event; 5 var message = '是否離開(kāi)此頁(yè)?'; 6 evt.returnValue = message; 7 return message; 8 }); 1 5.鼠標(biāo)滾輪(mousewheel)和DOMMouseScroll 2 // 用于獲取鼠標(biāo)上下滾輪的距離; 3 addEvent(docuemnt,'mousewheel',function(evt){ // 非Firefox; 4 alert(getWD(evt)); 5 }); 6 addEvent(docuemnt,'DOMMouseScroll',function(evt){ // Firefox; 7 alert(getWD(evt)); 8 }); 9 10 function getWD(evt){ 11 var e = evt || window.event; 12 if(e.wheelDelta){ // mousewheel事件的滾動(dòng)值保存在wheelDelta里; 13 return e.wheelDelta; 14 }else if(e.detail){ // DOMMouseScroll事件的滾動(dòng)值保存在detail里; 15 return -evt.detail*30; // 保持計(jì)算的統(tǒng)一; 16 } 17 } |
|
來(lái)自: 昵稱(chēng)10504424 > 《工作》