JavaScript 事件綁定及深入
事件綁定分為兩種:
一種是傳統(tǒng)事件綁定(內(nèi)聯(lián)模型/腳本模型);上一章內(nèi)容;
一種是現(xiàn)代事件綁定(DOM2級(jí)模型);現(xiàn)代事件綁定在傳統(tǒng)事件綁定基礎(chǔ)上提供了更強(qiáng)大的功能;
一 傳統(tǒng)事件綁定的問(wèn)題
// 腳本模型將一個(gè)函數(shù)賦值給一個(gè)事件處理函數(shù);
var box = document.getElementById('box'); // 獲取元素;
box.onclick = function(){ // 元素點(diǎn)擊觸發(fā)事件;
alert('Lee');
}
// 問(wèn)題一:一個(gè)事件處理函數(shù)觸發(fā)兩次事件;
window.onload = function(){ // 第一組程序;
alert('Lee');
}
window.onload = function(){ // 第二組程序;
alert('Mr.Lee');
}
// PS:當(dāng)兩組程序同時(shí)執(zhí)行的時(shí)候,后面一個(gè)會(huì)把前面一個(gè)完全覆蓋;
// 導(dǎo)致前面的window.onload完全失效了;
// 解決方案:
window.onload = function(){ // 第一組事件處理程序,會(huì)被覆蓋;
alert('Lee');
}
if(typeof window.onload == 'function'){ // 判斷之前是否有window.onload;
var saved = null; // 創(chuàng)建一個(gè)保存器;
saved = window.onload; // 把之前的window.onload保存起來(lái);
}
window.onload = function(){ // 下一個(gè)要執(zhí)行的事件;
// saved()=window.onload = function
if(saved)saved(); // 判斷之前是否有事件,如果有則先執(zhí)行之前保存的事件;
alert('Mr.Lee'); // 執(zhí)行本事件的代碼;
}
// 問(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傳遞到切換器里;
}
// 綜上三個(gè)問(wèn)題:覆蓋問(wèn)題/可讀性問(wèn)題/this傳遞為題;
// 我們創(chuàng)建一個(gè)自定義事件處理函數(shù);
function addEvent(obj,type,fn){ // 取代傳統(tǒng)事件處理函數(shù);
var saved = null; // 保存每次觸發(fā)的事件處理函數(shù);
if(typeof obj['on'+type] == 'function'){// 判斷是不是存在事件;
saved = obj['on'+type]; // 如果有,保存起來(lái);
}
obj['on'+type] = function(){ // 然后執(zhí)行;
if(saved)saved(); // 執(zhí)行上一個(gè);
fn.call(this); // 執(zhí)行函數(shù),把this傳遞進(jìn)去;
}
}
addEvent(window,'load',function(){
alert('Lee'); // 可以執(zhí)行;
});
addEvent(window.'load',function(){
alert('Mr.Lee'); // 可以執(zhí)行;
})
// 用自定義事件函數(shù)注冊(cè)到切換器上查看效果:
addEvent(window,'load',function(){
var box = document.getElementById('box');
addEvent(box,'click',toBlue);
});
function toRed(){
this.className = 'red';
addEvent(this,'click',toBlue);
}
function toBlue(){
this.className = 'blue';
addEvent(this,'click',toRed);
二 W3C事件處理函數(shù)
// "DOM2級(jí)事件"定義了兩個(gè)方法,用于添加事件和刪除事件的處理程序:addEventListener()和removeEventListener();
// 所有DOM節(jié)點(diǎn)中都包含這兩個(gè)方法,并且它們都接收3個(gè)參數(shù):事件名/函數(shù)/冒泡或捕獲的布爾值(true表示捕獲,false表示冒泡);
window.addEventListener('load',function(){
alert('Lee');
},false);
window.addEventListener('load',function(){
alert('Mr.Lee');
},false);
// PS:W3C的事件綁定好處:1.不需要自定義了;2.可以屏蔽相同的函數(shù);3.可以設(shè)置冒泡和捕獲;
window.addEventListener('load',init,false); // 第一次執(zhí)行了;
window.addEventListener('load',init,false); // 第二次被屏蔽了;
function init(){
alert('Lee');
}
// 事件切換器
window.addEventListener('load',function(){
var box = document.getElementById('box');
box.addEventListener('click',function(){ // 不會(huì)被覆蓋/誤刪;
alert('Lee');
},false);
box.addEventListener('click',toBlue,false); // 引入切換;
},false);
function toRed(){
this.className = 'red';
this.removeEventListener('click',toRed,false); // 移除事件處理函數(shù);
this.addEventListener('click',toBlue,false); // 添加需要切換的事件處理函數(shù);
}
function toBlue(){
this.className = 'blue';
this.removeEventListener('click',toBlue,false);
this.addEventListener('click',toRed,false);
}
// 設(shè)置冒泡和捕獲階段
document.addEventListener('click',function(){
alert('document');
},true); // 設(shè)置為捕獲;
document.addEventListener('click',function(){
alert('Lee');
},false); // 設(shè)置為冒泡;
三 IE事件處理函數(shù)
// IE中實(shí)現(xiàn)了與DOM中類(lèi)似的兩個(gè)方法:attachEvent()和detachEvent();
// 這兩個(gè)方法接收相同的參數(shù):事件名和函數(shù);
// 在使用這兩組函數(shù)的時(shí)候,區(qū)別:
// 1.IE不支持捕獲,只支持冒泡;
// 2.IE添加事件不能屏蔽重復(fù)的函數(shù);
// 3.IE中的this指向的是window而不是DOM對(duì)象;
// 4.在傳統(tǒng)事件上,IE是無(wú)法接受到event對(duì)象的;但使用了attachEvent()卻可以;
window.attachEvent('onload',function(){
var box = document.getElementById('box');
box.attachEvent('onclick',toBlue);
});
function toRed(){
var that = window.event.srcElement;
that.className = 'red';
that.detachEvent('onclick',toRed);
that.attachEvent('onclick',toBlue);
}
function toBlue(){
var that = window.event.srcElement;
that.className = 'blue';
that.detachEvent('onclick',toBlue);
that.attachEvent('onclick',toRed);
}
// PS:IE不支持捕獲;
// IE不能屏蔽;
// IE不能傳遞this,可以call過(guò)去;
// 在傳統(tǒng)綁定上,IE是無(wú)法像W3C那樣通過(guò)傳參接受event對(duì)象;但如果使用了attachEvent()卻可以;
box.onclick = function(evt){
alert(evt); // undefined;
}
box.attachEvent('onclick',function(evt){
alert(evt); // object;
alert(evt.type); // click;
});
// 兼容IE和W3C的事件切換器函數(shù);
function addEvent(obj,type,fn){ // 添加事件處理程序兼容;
if(obj.addEventListener){
obj.addEventListener(type,fn);
}else if(obj.attachEvent){
obj.attachEvent('on'+type,fn);
}
}
function removeEvent(obj,type,fn){ // 移除事件處理程序兼容;
if(obj.removeEventListener){
obj.removeEventListener(type,fn);
}esle if(obj.detachEvent){
obj.detachEvent('on'+type,fn);
}
}
function getTarget(evt){ // 得到事件目標(biāo);
if(evt.target){
return evt.target;
}else if(window.event.srcEleemnt){
return window.event.srcElement;
}
}
四 事件對(duì)象補(bǔ)充
1.relatedTarget
// 這個(gè)屬性可以在mouseover和mouseout事件中獲取從哪里移入和從哪里移出的DOM對(duì)象;
box.onmouseover = function(evt){ // 鼠標(biāo)移入box;
alert(evt.relatedTarget); // 獲取移入box之前的那個(gè)元素;
}
box.onmouseout = function(evt){ // 鼠標(biāo)移出box;
alert(evt.relatedTarget); // 獲取移出box之后到的那個(gè)元素;
}
// IE提供了兩組與之對(duì)應(yīng)的屬性:fromElement和toElement;
// 兼容函數(shù)
function getEarget(evt){
var e = evt || window.event; // 得到事件對(duì)象;
if(e.srcElement){ // 如果支持srcElement,表示IE;
if(e.type == 'mouseover'){ // 如果是over事件;
return e.fromeElement; // 就使用from;
}else if(e.type == 'mouseout'){ // 如果是out;
return e.toElement; // 就使用to;
}
}else if(e.relatedTarget){ // 如果支持relatedTarget,表示W(wǎng)3C;
return e.relatedTarget;
}
}
2.阻止事件的默認(rèn)行為
// 一個(gè)超鏈接的默認(rèn)行為就點(diǎn)擊然后跳轉(zhuǎn)到指定的頁(yè)面;
// 那么阻止默認(rèn)行為就可以屏蔽跳轉(zhuǎn)的這種操作,而實(shí)現(xiàn)自定義操作;
// 取消事件默認(rèn)行為還有一種不規(guī)范的做法,就是返回false;
link.onclick = function(){
alert('Lee');
return false; // 直接返回false,就不會(huì)跳轉(zhuǎn)了;
}
// PS:雖然return false;可以實(shí)現(xiàn)這個(gè)功能,但有漏洞;
// 第一:代碼必須寫(xiě)到最后,這樣導(dǎo)致中間的代碼執(zhí)行后,有可能執(zhí)行不到return false;
// 第二:return false寫(xiě)到最前那么之后的自定義操作就失敗了;
// 解決方案:在最前面就阻止默認(rèn)行為,并且后面還能執(zhí)行代碼;
function preDef(evt){ // 跨瀏覽器兼容阻止默認(rèn)行為;
var e = evt || window.event;
if(e.preventDefault){
e.preventDefault(); // W3C,阻止默認(rèn)行為;
}else{
e.returnValue = false; // IE,阻止默認(rèn)行為;
}
}
3.上下文菜單事件contextmenu
// 當(dāng)我們右擊網(wǎng)頁(yè)的時(shí)候,會(huì)自動(dòng)出現(xiàn)windows自帶的菜單;
// 那么我們可以使用contextmenu事件來(lái)修改我們指定的菜單;但前提是把右擊的默認(rèn)行為取消;
addEvent(window,'load',function(){
var text = docuemnt.getElementById('text');
addEvent(text,'contextmenu',function(evt){ // 添加右鍵菜單事件處理程序;
var e = evt || window.event;
preDef(e); // 阻止默認(rèn)行為函數(shù);
var menu = document.getElementById('menu'); // 找到自定義的menu對(duì)象;
menu.style.left = e.clientX+'px'; // 確定自定義menu在屏幕上的位置;
menu.style.top = e.clientX+'px';
menu.style.visibility = 'visible'; // 設(shè)置自定義menu的屬性為可見(jiàn);
addEvent(document,'click',function(){ // 給document添加單擊事件處理程序;
docuemnt.getElementById('myMenu').style.visibility = 'hidden'; //將自定義的menu隱藏;
});
});
});
4.卸載前事件beforeunload
// 這個(gè)事件可以幫助在離開(kāi)本頁(yè)的時(shí)候給出相應(yīng)的提示;"離開(kāi)"或"返回"操作;
addEvent(window.'beforeunload',function(evt){
var evt = event || window.event;
var message = '是否離開(kāi)此頁(yè)?';
evt.returnValue = message;
return message;
});
5.鼠標(biāo)滾輪(mousewheel)和DOMMouseScroll
// 用于獲取鼠標(biāo)上下滾輪的距離;
addEvent(docuemnt,'mousewheel',function(evt){ // 非Firefox;
alert(getWD(evt));
});
addEvent(docuemnt,'DOMMouseScroll',function(evt){ // Firefox;
alert(getWD(evt));
});
function getWD(evt){
var e = evt || window.event;
if(e.wheelDelta){ // mousewheel事件的滾動(dòng)值保存在wheelDelta里;
return e.wheelDelta;
}else if(e.detail){ // DOMMouseScroll事件的滾動(dòng)值保存在detail里;
return -evt.detail*30; // 保持計(jì)算的統(tǒng)一;
}
}
- JS 事件綁定、事件監(jiān)聽(tīng)、事件委托詳細(xì)介紹
- javascript實(shí)現(xiàn)簡(jiǎn)單的on事件綁定
- javascript事件綁定學(xué)習(xí)要點(diǎn)
- js事件綁定快捷鍵以ctrl+k為例
- Node.js中使用事件發(fā)射器模式實(shí)現(xiàn)事件綁定詳解
- JS的事件綁定深入認(rèn)識(shí)
- 淺談JavaScript之事件綁定
- JS 事件綁定函數(shù)代碼
- div+css+js模擬tab切換效果 事件綁定 IE,firefox兼容
- Javascript 事件流和事件綁定
- javaScript 事件綁定、事件冒泡、事件捕獲和事件執(zhí)行順序整理總結(jié)
相關(guān)文章
getElementById().innerHTML與getElementById().value的區(qū)別
這篇文章主要介紹了getElementById().innerHTML與getElementById().value的區(qū)別,因?yàn)榻?jīng)常有新手朋友問(wèn)到,特整理一下,需要的朋友可以參考下2016-10-10
JS簡(jiǎn)單實(shí)現(xiàn)登陸驗(yàn)證附效果圖
實(shí)現(xiàn)登陸驗(yàn)證的方法有很多,在本文為大家詳細(xì)介紹下使用js是如何做到的,下面有個(gè)不錯(cuò)的示例還有運(yùn)行截圖,喜歡的朋友可以嘗試操作下2013-11-11
JavaScript中Cookies的相關(guān)使用教程
這篇文章主要介紹了JavaScript中Cookies的相關(guān)使用教程,包括Cookies的存儲(chǔ)和刪除等操作方法,需要的朋友可以參考下2015-06-06
JavaScript中的正則表達(dá)式簡(jiǎn)明總結(jié)
這篇文章主要介紹了JavaScript中的正則表達(dá)式,簡(jiǎn)明總結(jié)了正則中的語(yǔ)法含義和RegExp對(duì)象,需要的朋友可以參考下2014-04-04
淺析JavaScript 箭頭函數(shù) generator Date JSON
下面小編就為大家?guī)?lái)一篇淺析JavaScript 箭頭函數(shù) generator Date JSON。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-05-05
解析js如何獲取當(dāng)前url中的參數(shù)值并復(fù)制給input
本篇文章是對(duì)js獲取當(dāng)前url中的參數(shù)值并復(fù)制給input的方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06
簡(jiǎn)單解析JavaScript中的__proto__屬性
這篇文章主要介紹了JavaScript中的__proto__屬性,對(duì)于JavaScript中所謂的對(duì)象來(lái)講,它指向?qū)ο蟮脑蚿rototype,需要的朋友可以參考下2016-05-05

