詳解javascript實(shí)現(xiàn)自定義事件
我們平時在操作dom時候經(jīng)常會用到onclick,onmouseover等一系列瀏覽器特定行為的事件,
那么自定義事件,顧名思義,就是自己定義事件類型,自己定義事件處理函數(shù),在合適的時候需要哪個事件類型,就去調(diào)用哪個處理程序
1.js所支持的瀏覽器默認(rèn)事件
瀏覽器特定行為的事件,或者叫系統(tǒng)事件,js默認(rèn)事件等等都行,大家知道我指的什么就行,下文我叫他js默認(rèn)事件。
js默認(rèn)事件的事件綁定,事件移出等一系列操作,相信大家都有用到過,如:
//DOM0級事件處理程序
var oDiv = document.getElementById('oDiv');
oDiv.onclick = function(){
alert("你點(diǎn)擊了我");
}
又或者
//DOM2級事件處理程序
var oDiv = document.getElementById('oDiv');
//非ie
oDiv.addEventListener("click",function(){
alert("你點(diǎn)擊了我");
},false);
//ie
oDiv.attachEvent("onclick", function(){
alert("你點(diǎn)擊了我");
});
所有我就不做過多的研究,畢竟我們來討論js自定義事件,這里給出一個我之前封裝過的處理js默認(rèn)事件的代碼:
//跨瀏覽器的事件處理程序
//調(diào)用時候直接用domEvent.addEvent( , , );直接調(diào)用
//使用時候,先用addEvent添加事件,然后在handleFun里面直接寫其他函數(shù)方法,如getEvent;
//addEventListener和attachEvent---都是dom2級事件處理程序
var domEvent = {
//element:dom對象,event:待處理的事件,handleFun:處理函數(shù)
//事件名稱,不含“on”,比如“click”、“mouseover”、“keydown”等
addEvent:function(element,event,handleFun){
//addEventListener----應(yīng)用于mozilla
if(element.addEventListener){
element.addEventListener(event,handleFun,false);
}//attachEvent----應(yīng)用于IE
else if(element.attachEvent){
element.attachEvent("on"+event,handleFun);
}//其他的選擇dom0級事件處理程序
else{
//element.onclick===element["on"+event];
element["on"+event] = handleFun;
}
},
//事件名稱,含“on”,比如“onclick”、“onmouseover”、“onkeydown”等
removeEvent:function(element,event,handleFun){
//removeEventListener----應(yīng)用于mozilla
if (element.removeEventListener) {
element.removeEventListener(event,handleFun,false);
}//detachEvent----應(yīng)用于IE
else if (element.detachEvent) {
element.detachEvent("on"+event,handleFun);
}//其他的選擇dom0級事件處理程序
else {
element["on"+event] = null;
}
},
//阻止事件冒泡
stopPropagation:function(event){
if(event.stopPropagation){
event.stopPropagation();
}else{
event.cancelBubble = true;//IE阻止事件冒泡,true代表阻止
}
},
//阻止事件默認(rèn)行為
preventDefault:function(event){
if(event.preventDefault){
event.preventDefault();
}else{
event.returnValue = false;//IE阻止事件冒泡,false代表阻止
}
},
//獲得事件元素
//event.target--非IE
//event.srcElement--IE
getElement:function(event){
return event.target || event.srcElement;
},
//獲得事件
getEvent:function(event){
return event? event : window.event;
},
//獲得事件類型
getType:function(event){
return event.type;
}
};
接下類我們不如正題,js自定義事件
2.對象直接量封裝js自定義事件
根據(jù)上面的封裝,我們可以這樣構(gòu)思
var eventTarget = {
addEvent: function(){
//添加事件
},
fireEvent: function(){
//觸發(fā)事件
},
removeEvent: function(){
//移除事件
}
};
相信這樣大家還是比較好理解的,然后又有一個問題大家可以想到,那就是,js默認(rèn)事件,js可以一一對應(yīng),知道那個是那個,那么我們的自定義事件呢,這個一一對應(yīng)的映射表只能我們自己去建立,然后我這樣
var eventTarget = {
//保存映射
handlers:{},
addEvent: function(){
//處理代碼
},
fireEvent: function(){
//觸發(fā)代碼
},
removeEvent: function(){
//移出代碼
}
};
我是這樣構(gòu)建這個映射關(guān)系的
handlers = {
"type1":[
"fun1",
"fun2",
// "..."
],
"type2":[
"fun1",
"fun2"
// "..."
]
//"..."
}
這樣每一個類型可以有多個處理函數(shù),以便于我們以后擴(kuò)充
接下來就是代碼方面的實(shí)戰(zhàn)的,編寫具體的處理代碼了…
相信大家對于這個思路已經(jīng)很清楚了,我直接附上代碼
//直接量處理js自定義事件
var eventTarget = {
//保存事件類型,處理函數(shù)數(shù)組映射
handlers:{},
//注冊給定類型的事件處理程序,
//type -> 自定義事件類型, handler -> 自定義事件回調(diào)函數(shù)
addEvent: function(type, handler){
//判斷事件處理數(shù)組是否有該類型事件
if(eventTarget.handlers[type] == undefined){
eventTarget.handlers[type] = [];
}
//將處理事件push到事件處理數(shù)組里面
eventTarget.handlers[type].push(handler);
},
//觸發(fā)一個事件
//event -> 為一個js對象,屬性中至少包含type屬性,
//因?yàn)轭愋褪潜仨毜?,其次可以傳一些處理函?shù)需要的其他變量參數(shù)。(這也是為什么要傳js對象的原因)
fireEvent: function(event){
//判斷是否存在該事件類型
if(eventTarget.handlers[event.type] instanceof Array){
var _handler = eventTarget.handlers[event.type];
//在同一個事件類型下的可能存在多種處理事件,找出本次需要處理的事件
for(var i = 0; i < _handler.length; i++){
//執(zhí)行觸發(fā)
_handler[i](event);
}
}
},
//注銷事件
//type -> 自定義事件類型, handler -> 自定義事件回調(diào)函數(shù)
removeEvent: function(type, handler){
if(eventTarget.handlers[type] instanceof Array){
var _handler = eventTarget.handlers[type];
//在同一個事件類型下的可能存在多種處理事件,找出本次需要處理的事件
for(var i = 0; i < _handler.length; i++){
//找出本次需要處理的事件下標(biāo)
if(_handler[i] == handler){
break;
}
}
//刪除處理事件
_handler.splice(i, 1);
}
}
};
這是一種調(diào)用運(yùn)行的方法
eventTarget.addEvent("eat",function(){
console.log(123); //123
});
eventTarget.fireEvent({type: "eat"});
這種方法有一個缺點(diǎn),不能刪除該處理事件,因?yàn)槲覀兪怯糜成浔碜龅?,而且也不提倡,直接給映射表里面存這么多數(shù)據(jù),有點(diǎn)多。
另一種方法,將處理事件提取出來(推薦)
function b(){
console.log(123);
}
eventTarget.addEvent("eat",b);
eventTarget.fireEvent({
type: "eat"
}); //123
eventTarget.removeEvent("eat",b);
eventTarget.fireEvent({type: "eat"}); //空
也可以這樣,傳遞更多的參數(shù)
eventTarget.fireEvent({
type: "eat",
food: "banana"
});
function b(data){
console.log(data.food); //banana
}
總結(jié):字面量這種方法,有點(diǎn)兒缺點(diǎn),就是萬一一不小心,把某個屬性在handler函數(shù)里面,賦值null,這樣會造成我們的的eventTarget 方法崩盤。看來原型應(yīng)該是個好方法,更安全一點(diǎn)。
3.對象原型封裝js自定義事件
由于前面思路基本都講清楚了,這里我直接附上代碼,大家可以研究下其中的利弊,或許你可以找到更好的方法解決Ta…
//自定義事件構(gòu)造函數(shù)
function EventTarget(){
//事件處理程序數(shù)組集合
this.handlers = {};
}
//自定義事件的原型對象
EventTarget.prototype = {
//設(shè)置原型構(gòu)造函數(shù)鏈
constructor: EventTarget,
//注冊給定類型的事件處理程序,
//type -> 自定義事件類型, handler -> 自定義事件回調(diào)函數(shù)
addEvent: function(type, handler){
//判斷事件處理數(shù)組是否有該類型事件
if(typeof this.handlers[type] == 'undefined'){
this.handlers[type] = [];
}
//將處理事件push到事件處理數(shù)組里面
this.handlers[type].push(handler);
},
//觸發(fā)一個事件
//event -> 為一個js對象,屬性中至少包含type屬性,
//因?yàn)轭愋褪潜仨毜?,其次可以傳一些處理函?shù)需要的其他變量參數(shù)。(這也是為什么要傳js對象的原因)
fireEvent: function(event){
//模擬真實(shí)事件的event
if(!event.target){
event.target = this;
}
//判斷是否存在該事件類型
if(this.handlers[event.type] instanceof Array){
var handlers = this.handlers[event.type];
//在同一個事件類型下的可能存在多種處理事件,找出本次需要處理的事件
for(var i = 0; i < handlers.length; i++){
//執(zhí)行觸發(fā)
handlers[i](event);
}
}
},
//注銷事件
//type -> 自定義事件類型, handler -> 自定義事件回調(diào)函數(shù)
removeEvent: function(type, handler){
//判斷是否存在該事件類型
if(this.handlers[type] instanceof Array){
var handlers = this.handlers[type];
//在同一個事件類型下的可能存在多種處理事件
for(var i = 0; i < handlers.length; i++){
//找出本次需要處理的事件下標(biāo)
if(handlers[i] == handler){
break;
}
}
//從事件處理數(shù)組里面刪除
handlers.splice(i, 1);
}
}
};
調(diào)用方法
function b(){
console.log(123);
}
var target = new EventTarget();
target.addEvent("eat", b);
target.fireEvent({
type: "eat"
}); //123
原型這種方法,與直接量方法功能是一樣的…
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助。
相關(guān)文章
AJAX使用了UpdatePanel后無法使用alert彈出腳本
今天在做項(xiàng)目的時候發(fā)現(xiàn)個問題。。使用UpdatePanel后alert腳本就要報(bào)錯了。2010-04-04
談?wù)処ntersectionObserver懶加載的具體使用
這篇文章主要介紹了談?wù)処ntersectionObserver懶加載的具體使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10
d3.js中冷門卻實(shí)用的內(nèi)置函數(shù)總結(jié)
D3.js是一個JavaScript庫,它可以通過數(shù)據(jù)來操作文檔。D3可以通過使用HTML、SVG和CSS把數(shù)據(jù)鮮活形象地展現(xiàn)出來。d3.js其實(shí)提供了很多內(nèi)置的函數(shù),可以卻被大家忽略了,下面這篇文章就來給大家詳細(xì)介紹了d3.js中冷門卻實(shí)用的一些內(nèi)置函數(shù),需要的朋友可以參考借鑒。2017-02-02

