JS自定義事件


自定義事件,就是自己定義事件類型,自己定義事件處理函數。

我們平時操作dom時經常會用到onclick、onmousemove等瀏覽器特定行為的事件類型。

封裝is自定義事件基本的構思:

var eventTarget = {
  addEvent: function(){
    //添加事件
  },
  fireEvent: function(){
    //觸發事件
  },
  removeEvent: function(){
    //移除事件
  }
};

在js默認事件中事件類型以及對應的執行函數是一一對應的,但是自定義事件,需要一個映射表來建立兩者之間的聯系。

如:  這樣每個類型可以處理多個事件函數

handlers = {
      "type1":[
            "fun1",
            "fun2",
            // "..."
         ],
       "type2":[
            "fun1",
            "fun2"
             // "..."
         ]
         //"..."
}

 

代碼實現:

function EventTarget(){
    //事件處理程序數組集合
    this.handlers={};
}

//自定義事件的原型對象
EventTarget.prototype={
    //設置原型構造函數鏈
    constructor:EventTarget,
    //注冊給定類型的事件處理程序
    //type->自定義事件類型,如click,handler->自定義事件回調函數
    addEvent:function(type,handler){
        //判斷事件處理函數中是否有該類型事件
        if(this.handlers[type]==undefined){
            this.handlers[type]=[];
        }
        this.handlers[type].push(handler);
    },

    //觸發事件
    //event為一個js對象,屬性中至少包含type屬性。
    fireEvent:function(event){
        //模擬真實事件的event
        if(!event.target){
            event.target=this;
        }
        //判斷是否存在該事件類型
        if(this.handlers[event.type] instanceof Array){
            var items=this.handlers[event.type];
            //在同一事件類型下可能存在多個事件處理函數,依次觸發
            //執行觸發
            items.forEach(function(item){
                item(event);
            })
        }
    },

    //刪除事件
    removeEvent:function(type,handler){
        //判斷是否存在該事件類型
        if(this.handlers[type] instanceof Array){
            var items=this.handlers[type];
            //在同一事件類型下可能存在多個處理事件
            for(var i=0;i<items.length;i++){
                if(items[i]==handler){
                    //從該類型的事件數組中刪除該事件
                    items.splice(i,1);
                    break;
                }
            }    
        }
    }    
}
            
//調用方法
function fun(){
    console.log('執行該方法');
}
function fun1(obj){
    console.log('run '+obj.min+'s');
}
var target=new EventTarget();
target.addEvent("run",fun);//添加事件
target.addEvent("run",fun1);//添加事件

target.fireEvent({type:"run",min:"30"});//執行該方法   123

target.removeEvent("run",fun);//移除事件

target.fireEvent({type:"run",min:"20"});//123

 

為什么要把方法添加到對象原型上?

在構造函數中加屬性,在原型中加方法。

將屬性和方法都寫在構造函數里是沒有問題的,但是每次進行實例化的過程中,要重復創建功能不變的方法。

由於方法本質上是函數,其實也就是在堆內存中又新建了一個對象空間存放存儲函數,造成了不必要的資源浪費。

在本身添加會導致每次對象實例化時代碼被復制,都需要申請一塊內存存放該方法。

 

寫一個EventEmitter類,包括on()、off()、once()、emit()方法

once():為指定事件注冊一個單次監聽器,單次監聽器最多只觸發一次,觸發后立即解除監聽器。

class EventEmitter{
            constructor(){
                this.handlers={};
            }
            on(type,fn){
                if(!this.handlers[type]){
                    this.handlers[type]=[];
                }
                this.handlers[type].push(fn);
                return this;
            }
            off(type,fn){
                let fns=this.handlers[type];
                for(let i=0;i<fns.length;i++){
                    if(fns[i]==fn){
                        fns.splice(i,1);
                        break;
                    }
                }
                return this;
            }
            emit(...args){
                let type=args[0];
                let params=[].slice.call(args,1);
                let fn=this.handlers[type];
                fn.forEach((item)=>{
                    item.apply(this,params);//執行函數
                })
                return this;
            }
            once(type,fn){
                let wrap=(...args)=>{
                    fn.apply(this,args);//執行事件后刪除
                    this.off(type,wrap);
                }
                this.on(type,wrap);//再添加上去
                return this;
            }
        }
        
        let emitter=new EventEmitter();
        function fun1(){
            console.log('fun1');
        }
        function fun2(){
            console.log('fun2');
        }
        function fun3(){
            console.log('fun3');
        }
        emitter.on('TEST1',fun1).on('TEST2',fun2).emit('TEST1').once('TEST2',fun3);
        emitter.emit("TEST2");

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM