使用過
jQuery
的同窗,應該對事件綁定方法.on()
.off()
有必定的瞭解。 在我的類庫jTool 中實現了這兩個方法,這裏就來細說下原生實現方式。前端
如下爲我的類庫jTool 中 Event 實現方式。 代碼中使用到一個基礎方法對象utilities ,該對象爲jTool 的基礎類。 若是想了解更多,能夠經過點擊進入查看原碼。node
首先經過一個空架子來了解下實現邏輯,核心實如今getEventObject() 方法內的包裝函數git
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
方法,傳入參數github
調用getEventObject()
獲取事件對象bash
調用removeEvent()
方法解除事件綁定前端框架
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()
使用事件代理。 事件代理是一種事件預綁定機制, 該機制能夠在事件節點不存在的狀況下, 將事件綁定至已存在父級節點之上的方式。app
隨筆一行 這是前端最好的時代, 這也是前端最壞的時代。 衆多前端框架滿天飛,隨着 jQuery 在前端行業的慢慢弱化,老是會有一種斯人遠去,何者慰籍的感受。互勉吧,各位。框架
另推薦個表格組件gridManagerdom