我們平時在操作dom時候經常會用到onclick,onmouseover等一系列浏覽器特定行為的事件,
那麼自定義事件,顧名思義,就是自己定義事件類型,自己定義事件處理函數,在合適的時候需要哪個事件類型,就去調用哪個處理程序
1.js所支持的浏覽器默認事件
浏覽器特定行為的事件,或者叫系統事件,js默認事件等等都行,大家知道我指的什麼就行,下文我叫他js默認事件。
js默認事件的事件綁定,事件移出等一系列操作,相信大家都有用到過,如:
//DOM0級事件處理程序 var oDiv = document.getElementById('oDiv'); oDiv.onclick = function(){ alert("你點擊了我"); }
又或者
//DOM2級事件處理程序 var oDiv = document.getElementById('oDiv'); //非ie oDiv.addEventListener("click",function(){ alert("你點擊了我"); },false); //ie oDiv.attachEvent("onclick", function(){ alert("你點擊了我"); });
所有我就不做過多的研究,畢竟我們來討論js自定義事件,這裡給出一個我之前封裝過的處理js默認事件的代碼:
//跨浏覽器的事件處理程序 //調用時候直接用domEvent.addEvent( , , );直接調用 //使用時候,先用addEvent添加事件,然後在handleFun裡面直接寫其他函數方法,如getEvent; //addEventListener和attachEvent---都是dom2級事件處理程序 var domEvent = { //element:dom對象,event:待處理的事件,handleFun:處理函數 //事件名稱,不含“on”,比如“click”、“mouseover”、“keydown”等 addEvent:function(element,event,handleFun){ //addEventListener----應用於mozilla if(element.addEventListener){ element.addEventListener(event,handleFun,false); }//attachEvent----應用於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----應用於mozilla if (element.removeEventListener) { element.removeEventListener(event,handleFun,false); }//detachEvent----應用於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代表阻止 } }, //阻止事件默認行為 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自定義事件
根據上面的封裝,我們可以這樣構思
var eventTarget = { addEvent: function(){ //添加事件 }, fireEvent: function(){ //觸發事件 }, removeEvent: function(){ //移除事件 } };
相信這樣大家還是比較好理解的,然後又有一個問題大家可以想到,那就是,js默認事件,js可以一一對應,知道那個是那個,那麼我們的自定義事件呢,這個一一對應的映射表只能我們自己去建立,然後我這樣
var eventTarget = { //保存映射 handlers:{}, addEvent: function(){ //處理代碼 }, fireEvent: function(){ //觸發代碼 }, removeEvent: function(){ //移出代碼 } };
我是這樣構建這個映射關系的
handlers = { "type1":[ "fun1", "fun2", // "..." ], "type2":[ "fun1", "fun2" // "..." ] //"..." }
這樣每一個類型可以有多個處理函數,以便於我們以後擴充
接下來就是代碼方面的實戰的,編寫具體的處理代碼了…
相信大家對於這個思路已經很清楚了,我直接附上代碼
//直接量處理js自定義事件 var eventTarget = { //保存事件類型,處理函數數組映射 handlers:{}, //注冊給定類型的事件處理程序, //type -> 自定義事件類型, handler -> 自定義事件回調函數 addEvent: function(type, handler){ //判斷事件處理數組是否有該類型事件 if(eventTarget.handlers[type] == undefined){ eventTarget.handlers[type] = []; } //將處理事件push到事件處理數組裡面 eventTarget.handlers[type].push(handler); }, //觸發一個事件 //event -> 為一個js對象,屬性中至少包含type屬性, //因為類型是必須的,其次可以傳一些處理函數需要的其他變量參數。(這也是為什麼要傳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++){ //執行觸發 _handler[i](event); } } }, //注銷事件 //type -> 自定義事件類型, handler -> 自定義事件回調函數 removeEvent: function(type, handler){ if(eventTarget.handlers[type] instanceof Array){ var _handler = eventTarget.handlers[type]; //在同一個事件類型下的可能存在多種處理事件,找出本次需要處理的事件 for(var i = 0; i < _handler.length; i++){ //找出本次需要處理的事件下標 if(_handler[i] == handler){ break; } } //刪除處理事件 _handler.splice(i, 1); } } };
這是一種調用運行的方法
eventTarget.addEvent("eat",function(){ console.log(123); //123 }); eventTarget.fireEvent({type: "eat"});
這種方法有一個缺點,不能刪除該處理事件,因為我們是用映射表做的,而且也不提倡,直接給映射表裡面存這麼多數據,有點多。
另一種方法,將處理事件提取出來(推薦)
function b(){ console.log(123); } eventTarget.addEvent("eat",b); eventTarget.fireEvent({ type: "eat" }); //123 eventTarget.removeEvent("eat",b); eventTarget.fireEvent({type: "eat"}); //空
也可以這樣,傳遞更多的參數
eventTarget.fireEvent({ type: "eat", food: "banana" }); function b(data){ console.log(data.food); //banana }
總結:字面量這種方法,有點兒缺點,就是萬一一不小心,把某個屬性在handler函數裡面,賦值null,這樣會造成我們的的eventTarget 方法崩盤。看來原型應該是個好方法,更安全一點。
3.對象原型封裝js自定義事件
由於前面思路基本都講清楚了,這裡我直接附上代碼,大家可以研究下其中的利弊,或許你可以找到更好的方法解決Ta…
//自定義事件構造函數 function EventTarget(){ //事件處理程序數組集合 this.handlers = {}; } //自定義事件的原型對象 EventTarget.prototype = { //設置原型構造函數鏈 constructor: EventTarget, //注冊給定類型的事件處理程序, //type -> 自定義事件類型, handler -> 自定義事件回調函數 addEvent: function(type, handler){ //判斷事件處理數組是否有該類型事件 if(typeof this.handlers[type] == 'undefined'){ this.handlers[type] = []; } //將處理事件push到事件處理數組裡面 this.handlers[type].push(handler); }, //觸發一個事件 //event -> 為一個js對象,屬性中至少包含type屬性, //因為類型是必須的,其次可以傳一些處理函數需要的其他變量參數。(這也是為什麼要傳js對象的原因) fireEvent: function(event){ //模擬真實事件的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++){ //執行觸發 handlers[i](event); } } }, //注銷事件 //type -> 自定義事件類型, handler -> 自定義事件回調函數 removeEvent: function(type, handler){ //判斷是否存在該事件類型 if(this.handlers[type] instanceof Array){ var handlers = this.handlers[type]; //在同一個事件類型下的可能存在多種處理事件 for(var i = 0; i < handlers.length; i++){ //找出本次需要處理的事件下標 if(handlers[i] == handler){ break; } } //從事件處理數組裡面刪除 handlers.splice(i, 1); } } };
調用方法
function b(){ console.log(123); } var target = new EventTarget(); target.addEvent("eat", b); target.fireEvent({ type: "eat" }); //123
原型這種方法,與直接量方法功能是一樣的…
以上就是本文的全部內容,希望對大家的學習有所幫助。