在團隊協做的不少狀況下,某個js的函數會根據不斷增長的需求進而不斷增長功能,若是功能需求累積過多,咱們就很難把控本身在這個函數中新定義的變量會不會覆蓋掉以前的定義。如:javascript
function action(){ console.log(1); console.log(2);//新增需求1 console.log(3);//新增需求2 ......//一直增長就很難保證下面的代碼不會與以前的代碼產生衝突 }
而若是咱們爲新增的需求從新定義一個同名的js方法,那後來定義的方法又會將以前定義的方法覆蓋,這固然也不是咱們想要的結果。如:java
function action(){console.log(1);} function action(){console.log(2);}//新增需求1 function action(){console.log(3);}//新增需求2
執行結果:3
git
那麼有沒有什麼辦法可讓咱們的函數分別執行,而且互不影響呢?是的,你必定想到了js事件。github
<!--more-->瀏覽器
說到js的事件,咱們立馬就會想到原生js中對事件的實現。在標準DOM瀏覽器中的addEventListener
、removeEventListener
和在IE中的attachEvent
、detachEvent
這些已經爲咱們熟知,而且綁定在同一個DOM中的相同的事件彼此不會被覆蓋,好比,你在某個div中綁定了3個click
事件,在執行時它們會按序執行,而不會只執行最後一次綁定:函數
//下面的例子僅實現標準DOM瀏覽器 oDiv.addEventListener("click",function(){console.log(1);},false); oDiv.addEventListener("click",function(){console.log(2);},false); oDiv.addEventListener("click",function(){console.log(3);},false);
執行結果:1 2 3spa
看起來恰好解決了咱們的各類顧慮,單獨定義,互不影響,頗有利於團隊協做,可是這些內置的事件綁定方式卻依然沒法直接解決咱們的問題。code
好吧,既然沒法直接解決,那咱們就利用頁面事件綁定的思想來本身探索,這就是咱們今天要介紹的自定義事件。對象
首先來看看什麼是自定義事件:讓函數可以具有事件的某些特性。 blog
其實自定義事件在一些主流的類庫中都有實現,後續會分析具體的實現方法。今天,咱們就先用簡單的例子來實現自定義事件的功能。
回到開始的時候咱們提出的需求:讓函數分別執行,而且互不影響。這就好像咱們要按照清單從圖書館借5本書,走出圖書館的時候,咱們手裏拿到的應該是想借的5本,而不是清單上的最後一本。
依照js的事件綁定方式來剖析一下這幾本書和圖書館之間的關係:
其中,圖書館就是咱們要綁定事件的對象,也就是咱們借書的對象,「click
」就是咱們綁定事件的類別,也就是咱們想要借的書的分類,而function回調就是咱們要執行的函數,也就是咱們想借的具體某本書。理清了對應關係,咱們就能夠從一個圖書館內不一樣的分類書架上拿到不一樣的書。
把這個對應的關係映射到自定義事件上就是:在某個對象上綁定不一樣類別的一個或多個方法,而且讓它們分別執行。接下來咱們就來實現一下這種關係。首先來看一下自定義事件的綁定實現:
//綁定 function on(obj,events,fn){//參數分別是:對象/自定義事件類別/方法 //初始化自定義監聽對象,若是存在繼續使用,不存在就建立新對象 obj.listeners = obj.listeners || {}; obj.listeners[events] = obj.listeners[events] || [];//初始化監聽的自定義事件列表 obj.listeners[events].push(fn);//將要執行的方法分別存放到對應事件的列表中 }
這樣,咱們就把想要執行的一系列方法綁定到了某個頁面對象對應的自定義事件類別上。方法綁定好了以後,如何去觸發呢?看下面的代碼實現:
//觸發 function fire(obj,events){//參數分別是:對象/自定義事件類別 for(var i = 0; i < obj.listeners[events].length; i++){//遍歷某個事件類別下全部的方法 obj.listeners[events][i]();//依次執行遍歷到的全部的方法 } }
這樣,咱們定義的想要去執行的每一個方法都能被執行,而且它們之間互不影響。看個實際的例子:
var eventHandle = { on: function(obj,events,fn){ obj.listeners = obj.listeners || {}; obj.listeners[events] = obj.listeners[events] || []; obj.listeners[events].push(fn); }, fire: function(obj,events){ for(var i = 0, n = obj.listeners[events].length; i < n; i++){ console.log(obj.listeners[events]); obj.listeners[events][i] && obj.listeners[events][i](); } }, off: function(obj,events){ for(var i = 0, n = obj.listeners[events].length; i < n; i++){ obj.listeners[events][i] = null; } } }; //綁定自定義事件, eventHandle.on(oDiv,"eventType1",function(){console.log(1);});//準備執行方法1 eventHandle.on(oDiv,"eventType1",function(){console.log(2);});//準備執行方法2 eventHandle.on(oDiv,"eventType1",function(){console.log(3);});//準備執行方法3 eventHandle.on(oDiv,"eventType2",function(){console.log(4);});//準備執行方法4 //觸發執行 eventHandle.fire(oDiv,"eventType1");//執行eventType1下的全部方法
執行結果:1 2 3
不執行方法4是由於,eventType2下的方法4僅僅被綁定,並無被觸發。