封裝庫-事件綁定

問題所在:

1 支持同一個元素的同一個事件句柄上可以綁定多個堅挺函數;
2 如果在同一個元素的同一個事件句柄上多次注冊同一個函數,那么除第一次注冊的函數,其余都將被忽略;
3 函數體內的this指向的應當是正在處理事件的節點(IE指向window);
4 監聽函數的執行順序應當是按照綁定的順序執行;
5 在函數體內不用使用 event = event || window.event,來標準化Event對象。

var btn = document.getElementById("btn"); btn.onclick = function () { alert('我是傳統事件綁定'); }
以上代碼展示的傳統的事件綁定?,F代綁定中W3C使用的是:addEventListener和removeEventListener.IE使用的是attachEvent和detachEvent.

    // 跨瀏覽器添加事件
     function addEvent(obj, type, fn) {
          if (typeof addEventListener != 'undefined')
               {
                 obj.addEventListener(type, fn, false);
                } else if (typeof attachEvent != 'undefined') 
                {
                   obj.attachEvent('on' + type, fn);
                }
           }```
  //跨瀏覽器刪除事件
  function removeEvent(obj, type, fn) {
      if (typeof removeEventListener != 'undefined')
          {
             obj.removeEventListener(type, fn);
          } else if (typeof detachEvent != 'undefined') 
            {
                obj.detachEvent('on' + type, fn);
            }
      }
以上的兩個函數解決了:***同時綁定多個函數以及標準化event的問題***。但是*IE多次注冊同一函數*,第一個除外的其他函數并未被忽略;IE中監聽函數的執行并不是按照綁定的順序進行執行,而是*倒序執行*。還有一個問題就是IE中*this傳遞過來的是window*,而不是當前正在運行事件句柄的節點。
為了解決this傳遞問題,我們需要使用匿名函數+傳遞參數的方式來解決:
`  obj.addEvent('on' + type,function(){
    fn.call(obj,window.event);
  });`
使用call第一個參數就是獲取this,從第二個參數開始,可以通過函數參數獲取。故以上代碼解決了IE中this指向window的問題,同時可以獲取到event對象。
但是這又引入了新的問題:***無法刪除事件  無法順序執行  IE的現代綁定存在內從泄露的問題。***

從上述問題我們可以看到主要問題是在IE的attachEvent上,存在著無法避免地內佛那個泄露問題。所以我們考慮使用傳統事件綁定對IE進行封裝。
//跨瀏覽器添加事件綁定
function addEvent(obj, type, fn) {
    if (typeof obj.addEventListener != 'undefined') {
        obj.addEventListener(type, fn, false);
    } else {
          //創建一個可以保存事件的哈希表(散列表)
           if (!obj.events) obj.events = {};
           if (!obj.events[type]) {
                //創建一個可以保存事件處理函數的數組
              obj.events[type] = [];
              //存儲第一個事件處理函數
              if (obj['on' + type])  obj.events[type][0] = fn;
            }
            //通過事件計數器來從第二個事件處理函數開始
            obj.events[type][addEvent.ID++] = fn;
             //執行所有事件處理函數
            obj['on' + type] = function () {
            for (var i in obj.events[type]) {
                obj.events[type][i]();
              }
          }
      }
  }

 //每個事件分配一個ID 計數器
 addEvent.ID = 1;
//事件處理函數調用
addEvent.exec = function (event) {
    var e = event || addEvent.fixEvent(window.event);
    var es = this.events[e.type];
    for (var i in es) {
        es[i].call(this, e);
    }
 };

//獲取IE 的event,兼容W3C 的調用
addEvent.fixEvent = function (event) {
    event.preventDefault = addEvent.fixEvent.preventDefault;
    event.stopPropagation = addEvent.fixEvent.stopPropagation;
    return event;
};

//兼容IE 和W3C 阻止默認行為
addEvent.fixEvent.preventDefault = function () {
    this.returnValue = false;
};

//兼容IE 和W3C 取消冒泡
addEvent.fixEvent.stopPropagation = function () {
    this.cancelBubble = true;
};

//跨瀏覽器刪除事件
function removeEvent(obj, type, fn) {
    if (typeof obj.removeEventListener != 'undefined') {
        obj.removeEventListener(type, fn, false);
    } else {
        var es = obj.events[type];
        for (var i in es) {
            if (es[i] == fn) {
            delete obj.events[type][i];
            }
        }
     }
  }
以上就是基于原聲JS自己封裝的事件綁定庫。后續的話需要研究下jQuery的源碼,看看關于事件綁定這部分的代碼。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 以下文章為轉載,對理解JavaScript中的事件處理機制很有幫助,淺顯易懂,特分享于此。 什么是事件? 事件(E...
    jxyjxy閱讀 3,075評論 1 10
  • 聲明:本文來源于http://www.webzsky.com/?p=731我只是在這里作為自己的學習筆記整理一下(...
    angryyan閱讀 7,130評論 1 6
  • 事件流: 事件流:頁面接收事件的順序。 IE定義的:事件冒泡流(由最具體的元素依次傳播到DOM樹的最上層的Docu...
    xiaoguo16閱讀 609評論 0 0
  • JavaScript的組成 JavaScript 由以下三部分組成:ECMAScript(核心):JavaScri...
    紋小艾閱讀 3,476評論 0 3
  • 飯桌上,他用小手指著遠處的一碗皮蛋辣椒,突然冒出了一句:“內個亞椒亞不亞?” 一旁給他準備食物的我還摸不著頭腦,于...
    SophieXiong閱讀 609評論 0 1