使用過jQuery
的同窗,應該對事件綁定方法.on()
.off()
有必定的瞭解。 在我的類庫 jTool 中實現了這兩個方法,這裏就來細說下原生實現方式。
如下爲我的類庫 jTool 中 Event 實現方式。
代碼中使用到一個基礎方法對象 utilities ,該對象爲 jTool 的基礎類。 若是想了解更多,能夠經過點擊進入查看原碼。
首先經過一個空架子來了解下實現邏輯,核心實如今getEventObject() 方法內的包裝函數
var Event = { // 綁定 on: function(event, querySelector, callback, useCapture){ return this.addEvent(this.getEventObject(event, querySelector, callback, useCapture)); }, // 解除綁定 off: function(event, querySelector) { return this.removeEvent(this.getEventObject(event, querySelector)); }, // 獲取 jTool Event 對象 getEventObject: function (event, querySelector, callback, useCapture){ // 事件代理實現核心 // 注意: 這個方法爲包裝函數,此處的this爲觸發事件的Element var fn = callback; callback = function(e){ // 驗證子選擇器所匹配的nodeList中是否包含當前事件源 或 事件源的父級 // 注意: 這個方法爲包裝函數,此處的this爲觸發事件的Element var target = e.target; while(target !== this ){ if([].indexOf.call( this.querySelectorAll(querySelector), target) !== -1){ fn.apply(target, arguments); break; } target = target.parentNode; } }; return { eventName: event + querySelector, type: event, querySelector: querySelector, callback: callback || utilities.noop, useCapture: useCapture || false }; }, // 增長事件,並將事件對象存儲至DOM節點 addEvent: function (eventList){ }, // 刪除事件,並將事件對象移除出DOM節點 removeEvent: function (eventList){ } }
jTool
實例的on
方法,傳入參數getEventObject()
獲取事件對象addEvent()
方法進行事件綁定經過調用jTool
實例的off
方法,傳入參數前端
調用getEventObject()
獲取事件對象node
調用removeEvent()
方法解除事件綁定git
var _Event = { on: function(event, querySelector, callback, useCapture) { // 將事件觸發執行的函數存儲於DOM上, 在清除事件時使用 }, off: function(event, querySelector) { return this.removeEvent(this.getEventObject(event, querySelector)); }, bind: function(event, callback, useCapture) { return this.on(event, undefined, callback, useCapture); }, unbind: function(event) { return this.removeEvent(this.getEventObject(event)); }, // 獲取 jTool Event 對象 getEventObject: function(event, querySelector, callback, useCapture) { // $(dom).on(event, callback); if (typeof querySelector === 'function') { useCapture = callback || false; callback = querySelector; querySelector = undefined; } // event callback 爲必要參數 if (!event) { utilities.error('事件綁定失敗,緣由: 參數中缺失事件類型'); return this; } // 子選擇器不存在 或 當前DOM對象包含Window Document 則將子選擇器置空 if(!querySelector || utilities.type(this.DOMList[0]) !== 'element'){ querySelector = ''; } // #Event003 存在子選擇器 -> 包裝回調函數, 回調函數的參數 // 預綁定功能實現 if(querySelector !== ''){ var fn = callback; callback = function(e){ // 驗證子選擇器所匹配的nodeList中是否包含當前事件源 或 事件源的父級 // 注意: 這個方法爲包裝函數,此處的this爲觸發事件的Element var target = e.target; while(target !== this ){ if([].indexOf.call( this.querySelectorAll(querySelector), target) !== -1){ fn.apply(target, arguments); break; } target = target.parentNode; } }; } var eventSplit = event.split(' '); var eventList = [], eventScopeSplit, eventObj; utilities.each(eventSplit, function(i, eventName) { if (eventName.trim() === '') { return true; } eventScopeSplit = eventName.split('.'); eventObj = { eventName: eventName + querySelector, type: eventScopeSplit[0], querySelector: querySelector, callback: callback || utilities.noop, useCapture: useCapture || false, // TODO: nameScope暫時不用 nameScope: eventScopeSplit[1] || undefined }; eventList.push(eventObj); }); return eventList; }, // 增長事件,並將事件對象存儲至DOM節點 addEvent: function(eventList) { var _this = this; utilities.each(eventList, function (index, eventObj) { utilities.each(_this.DOMList, function(i, v){ v.jToolEvent = v.jToolEvent || {}; v.jToolEvent[eventObj.eventName] = v.jToolEvent[eventObj.eventName] || []; v.jToolEvent[eventObj.eventName].push(eventObj); v.addEventListener(eventObj.type, eventObj.callback, eventObj.useCapture); }); }); return _this; }, // 刪除事件,並將事件對象移除出DOM節點 removeEvent: function(eventList) { var _this = this; var eventFnList; //事件執行函數隊列 utilities.each(eventList, function(index, eventObj) { utilities.each(_this.DOMList, function(i, v){ if (!v.jToolEvent) { return; } eventFnList = v.jToolEvent[eventObj.eventName]; if (eventFnList) { utilities.each(eventFnList, function(i2, v2) { v.removeEventListener(v2.type, v2.callback); }); v.jToolEvent[eventObj.eventName] = undefined; } }); }); return _this; } };
.on()
與.bind()
均可以進行事件綁定, 區別在於.on()
使用事件代理。 事件代理是一種事件預綁定機制, 該機制能夠在事件節點不存在的狀況下, 將事件綁定至已存在父級節點之上的方式。github
隨筆一行
這是前端最好的時代, 這也是前端最壞的時代。 衆多前端框架滿天飛,隨着 jQuery 在前端行業的慢慢弱化,老是會有一種斯人遠去,何者慰籍的感受。互勉吧,各位。前端框架
另推薦個表格組件gridManagerapp