1.思路
(1)構思
var eventTarget = { addEvent: function(){ //添加事件 }, fireEvent: function(){ //觸發事件 }, removeEvent: function(){ //移除事件 } };
(2)建立一一對應的映射表
var eventTarget = { //保存映射 handlers:{}, addEvent: function(){ //處理代碼 }, fireEvent: function(){ //觸發代碼 }, removeEvent: function(){ //移出代碼 } };
(3)構建映射關系
handlers = { "type1":[ "fun1", "fun2", // "..." ], "type2":[ "fun1", "fun2" // "..." ] //"..." }
這樣每一個類型可以有多個處理函數,以便於我們以后擴充
(4)構建后
//直接量處理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 }
(5)總結
//自定義事件構造函數 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
.