JavaScript移除綁定在元素上的匿名事件處理函數

前言:

面試的時候有點蒙,結束以後想一想本身好像根本就誤解了面試官的問題,由於我理解的這個問題自己就沒有意義。可是當時已經有一些思路,可是在一個點上被卡住。面試

結束以後腦子瞬間靈光,想出了當時沒有邁出的那一小步。因此不想計較這個問題自己的意義,單純的想要把這個我理解錯了的問題解決,就當是知足本身一個小小的願望吧。數組

 

問題:

用addEventListener()和attachEvent()給一個DOM元素綁定事件處理程序時,若是傳入一個匿名函數,那麼用相應的removeEventListener()和detachEvent()是沒法將這個匿名的處理程序解除綁定的。因此咱們用的時候應該傳入一個函數表達式。函數

那麼,若是我就是想使用匿名函數進行綁定和解綁,怎麼解決?this

 

思路:

既然這兩個函數都高冷的說明了不接受相同的匿名函數進行解綁,那麼就只能另尋出路,不能靠它來管理事件了。spa

因此須要一個自定義的對象來管理事件。prototype

事件處理程序的本質就是,當一個事件在一個對象上發生時,執行監聽這個事件的函數。翻譯

翻譯一下:code

一個DOM元素可能被綁定多個事件類型的處理程序。好比click的時候顏色改變,mouseover的時候變大。對象

一個事件類型可能綁定多個事件處理程序。好比mouseover的時候又變色又變大。blog

因此,這個事件對象應該有一個屬性用來存儲這個DOM元素上綁定的全部事件處理程序,還應該有兩個方法,一個用來添加,一個用來刪除。

{
handlers:{
type1:[handler1,handler2],
type2:[handler1,handler2],
...//其餘事件類型和對應的事件處理函數
},
on:function(){},
off:function(){}
}

當一個事件發生時,就調用這個對象裏面對應的事件類型的數組裏面的全部函數。

因此綁定事件就是往對應的數組裏面添加函數,解除綁定事件就是把這個函數從這個數組裏面刪掉。

那麼怎麼保證操做的是那個正確的DOM元素呢?

顯然,每一個DOM元素都應該須要一個這樣的對象,用於管理本身的事件處理程序。

每一個對象都有的東西,那不就是他的屬性嘛。(而我當時就被卡在了這裏)。

實現:

每一個DOM元素都須要這樣一個對象,並且每一個對象中的on()和off()方法都是相同的,因此須要一個構造函數,把這兩個方法放到他的原型對象中去。

function EventManage(){
  this.handlers={}
}
EventManage.prototype={
  on:function(type,handler){
    if(!this.handlers[type]){
      this.handlers[type]=[handler];
      return true;  //避免添加多個事件
    }else{
      this.handlers[type].push(handler);
    }
  },
  off:function(type,handler){
    for(var i=0,len=this.handlers[type].length;i<len;i++){
      if(this.handlers[type][i].toString()==handler.toString()){
        this.handlers[type].splice(i,1);
      }
    }
  }
}

每一個對象有了這兩個方法,就能夠自行添加和移除事件處理程序了,可是,監聽事件,仍是要靠JavaScript提供的方法,因此借用addEventListner()和attachEvent()來監聽事件:

var EventUtil={};
EventUtil.on=function(ele,type,handler){
  if (!ele.event) {
    ele.event=new EventManage();
  }
  var isNewType=ele.event.on(type,handler);
  var fire=function(){
      for(var i=0,len=ele.event.handlers[type].length;i<len;i++){
        ele.event.handlers[type][i]();
      }
    };
  if (isNewType) {
    if (ele.addEventListener) {
      ele.addEventListener(type,fire,false);
    }else{
      ele.attachEvent("on"+type,fire);
    }
  }
}
EventUtil.off=function(ele,type,handler){
  ele.event.off(type,handler);
}

這裏要注意一個問題,每次使用EventUtil.on()時都會從新定義一個fire函數,addEventListener()就會給相同的事件類型添加多個相同的事件處理程序,因此須要判斷一下這個事件類型是否是新增的,若是是的話再用addEventListener()來監聽這個事件類型。

 

使用示例:

var btn=document.getElementById("btn");

EventUtil.on(btn,"click",function(){
  console.log("11");
});
EventUtil.on(btn,"click",function(){
  console.log("22");
});
EventUtil.off(btn,"click",function(){
  console.log("11");
});

當點擊btn時,只打印了"22",說明匿名函數成功解綁。

相關文章
相關標籤/搜索