以前寫了篇文章《原生javascript實現相似jquery on方法的行爲監聽》比較淺顯,可以簡單的使用場景。javascript
這裏的自定義事件指的是區別javascript默認的與DOM交互的事件,好比click,mouseover,change等,有時候咱們須要監聽某一行爲是否發生,很顯然默認的行爲不夠用,好比一個場景。咱們寫好了tab切換,點擊後請求加載隱藏標籤的內容。html
tab切換是很是經常使用的一個功能,一般會寫成組件,若是每次把請求寫在組件裏確定對組件拓展和耦合性有影響。這時候咱們能夠在組件裏自定義一個事件廣播,在其餘地方監聽這個廣播再執行請求就能夠避免了。java
以上只是使用場景,下面是具體實現:jquery
一、簡易代碼,基礎功能:數組
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>自定義事件</title> </head> <body> <button id="demo">點我吧</button> <script type="text/javascript"> function Observer(){ this._events={}; } Observer.prototype={ on:function(eName,fn,scope){ eName=eName.toLowerCase(); this._events[eName]=[]; this._events[eName].push({fn:fn||null,scope:scope||null}); }, fireEvent:function(){ var args=Array.prototype.slice.call(arguments);//將參數轉爲數組 var eName=args.shift().toLowerCase(); var list=this._events[eName]; for(var i=0;i<list.length;i++){ var dict=list[i]; var fn=dict.fn; var scope=dict.scope; fn.apply(scope||null,args);//註冊事件執行 } } } var listener=new Observer(); listener.on("alert",function(name ,age){ console.log(name+":"+age); }); listener.on("aha",function(name ,age){ console.log("這是另一個事件"+name+":"+age); }); var $btn=document.getElementById("demo") $btn.onclick=function(){ listener.fireEvent('aha', '彼岸花再開', 28); } </script> </body> </html>
有點相似jquery裏面的on方法,$(ele).on(type,fn)。上面的on是註冊一個事件,這個事件是一個對象,存儲當前的事件名稱和函數。fireEvent能夠理解爲釋放,發射,監聽事件。app
完整的實現:函數
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>自定義事件</title> </head> <body> <button id="demo">點我吧</button> <script type="text/javascript"> function Observer() { this._events = {}; } Observer.prototype = { constructor: this, addEvent: function(eName, fn) { if (typeof(eName) === "string" && typeof(fn) === "function") { eName = eName.toLowerCase(); if (typeof(this._events[eName]) === "undefined") { this._events[eName] = [fn]; } else { this._events[eName].push(fn); } } return this; }, addEvents: function(obj) { //綁定多事件 obj = typeof(obj) === "object" ? obj : {}; for (var eName in obj) { if (eName && typeof(obj[eName] === "function")) { this.addEvent(eName, obj[eName]); } } return this; }, fireEvent: function(eName) { //觸發事件 if (eName && this._events[eName]) { var events = { eName: eName, target: this }; for (var length = this._events[eName].length, start = 0; start < length; start++) { this._events[eName][start].call(this, events); } } return this; }, fireEvents: function(array) { if (array instanceof Array) { for (var i = 0, len = array.length; i < len; i++) { this.fireEvent(array[i]); } } return this; }, removeEvent: function(eName, key) { //刪除綁定的事件 var eventsList = this._events[eName]; if (eventsList instanceof Array) { if (typeof(key) === "function") { for (var i = 0, len = eventsList.length; i < len; i++) { if (eventsList[i] === key) {//移除其中某個事件 eventsList.splice(i, 1); break; } } } else if (key instanceof Array) {//移除某個事件下面多個函數 for (var lis = 0, lenkey = key.length; lis < lenkey; lis += 1) { this.removeEvent(type, key[lenkey]); } } else {//直接移除事件下全部函數 delete this._events[eName]; } } return this; }, removeEvents: function(params) { if (params instanceof Array) { for (var i = 0, length = params.length; i < length; i += 1) { this.removeEvent(params[i]); } } else if (typeof params === "object") { for (var type in params) { this.removeEvent(type, params[type]); } } return this; } } var listeners = new Observer(); listeners.addEvents({ "once": function() { alert("該事件只會出現一次!"); this.removeEvent("once"); }, "infinity": function() { alert("每次點擊頁面,該事件都會!"); } }); document.onclick = function(e) { e = e || window.event; var target = e.target || e.srcElement; if (!target || !/button/i.test(target.tagName)) { listeners.fireEvents(["once", "infinity"]); } }; </script> </body> </html>
換apply實現,細心的你是否發現其中的差異呢:this
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>自定義事件</title> </head> <body> <button id="demo">點我吧</button> <script type="text/javascript"> function Observer() { this._events = {};//存儲事件對象 } Observer.prototype = { constructor: this, addEvent: function(eName, fn) {//綁定事件 if (typeof(eName) === "string" && typeof(fn) === "function") { eName = eName.toLowerCase(); if (typeof(this._events[eName]) === "undefined") { this._events[eName] = [{//將事件函數綁定到事件名稱 fn: fn }]; } else { this._events[eName].push({ fn: fn }); } } return this; }, addEvents: function(obj) { //綁定多事件 obj = typeof(obj) === "object" ? obj : {}; for (var eName in obj) { if (eName && typeof(obj[eName] === "function")) { this.addEvent(eName, obj[eName]); } } return this; }, fireEvent: function(eName) {//廣播事件,射吧! var args = Array.prototype.slice.call(arguments);//將參數轉爲數組 var eName = args.shift().toLowerCase();//第一個參數是事件名,這裏須要除時間名以外的參數 var list = this._events[eName]; if(list instanceof Array){ for (var i = 0; i < list.length; i++) { var dict = list[i]; var fn = dict.fn; fn.apply(null, args); } } return this; }, fireEvents: function(array) { if (array instanceof Array) { for (var i = 0, len = array.length; i < len; i++) { this.fireEvent(array[i]); } } return this; }, removeEvent: function(eName, key) { var eventsList = this._events[eName]; if (eventsList instanceof Array) { if (typeof(key) === "function") { for (var i = 0, len = eventsList.length; i < len; i++) { if (eventsList[i] === key) { eventsList.splice(i, 1); break; } } } else if (key instanceof Array) { for (var lis = 0, lenkey = key.length; lis < lenkey; lis += 1) { this.removeEvent(type, key[lenkey]); } }else{ delete this._events[eName]; } } } } var listeners = new Observer(); listeners.addEvents({ "once": function() { alert("該事件只會出現一次!"); listeners.removeEvent("once"); }, "infinity": function() { alert("每次點擊頁面,該事件都會出現!"); } }); document.onclick = function(e) { e = e || window.event; var target = e.target || e.srcElement; if (!target || !/input|pre/i.test(target.tagName)) { listeners.fireEvents(["once", "infinity"]); } }; </script> </body> </html>