正值初夏,瞭解一下JavaScript事件管理
highlight: agate theme: cyanosis
我正在參加「初夏創意投稿大賽」詳情請看:初夏創意投稿大賽
炎炎夏日 ,今天你學習了嗎?
當我們擁有一堆程式碼,且看不懂的時候,這個時候我們就該想該如何去重構該程式碼,此時我們就可以採用自定義事件管理的方式,能夠更好的管理維護程式碼,這個時候就會發起疑問了,為什麼要採用這種方式呢,個人認為自定義事件管理有以下優點: - 佔用記憶體小,專案啟動快,能夠很好的提高效能 - 減少事件註冊,不會覆蓋掉之前的相同事件 他的缺點也很明顯,因為它不會覆蓋掉之前相同的事件,就極有可能會出現事件混亂執行的情況,這裡需要注意一下
如何實現自定義事件管理
自定義事件管理,實現的方法有很多,我這裡講倆種方案,思路都是基本一樣,自定義事件管理是把所有事件放到一個地方統一管理,可以進行刪除,新增,觸發,儲存事件的地方叫做事件池,事件池存放了所有觸發元素和事件;
ES5實現方式
事件池:用於管理自定義事件
js //事件池 /** * 儲存後的資料:key是事件管理名,val是一個數組,裡面是事件 "mydom":['事件1','事件2'] **/ const handle={};
往事件池裡面新增事件
js
/**
EventName 事件管理名
fn 需要新增的事件
*/
function addEvent(EventName, fn) {
// 判斷事件名是否存在於事件池,如果不存在則建立一個空陣列
if (!(EventName in handle)) {
handle[EventName] = [];
};
// 新增進去
handle[EventName].push(fn);
};
刪除事件
js
/**
EventName 事件管理名
fn 需要刪除的事件
*/
function removeEvent(EventName, fn) {
// 判斷當前的事件管理名是否存在,不存在則退出
if (!(EventName in handle)) {
return;
};
let i = handle[EventName].findIndex(val => {
// 判斷當前的元素是否存在,存在返回當前元素的索引值,不存在則返回-1
return val == fn;
});
if (i == -1) {
// 沒有找到事件則退出
return console.error('沒有找到事件')
};
// 使用陣列方法刪除下標為i的陣列,操作的是原陣列
handle[EventName].splice(i, 1);
};
觸發事件
js
/**
EventName 事件管理名,用於事件名下管理的所有事件
*/
function triggerEvent(EventName) {
// 判斷當前的事件管理名是否存在,不存在則退出
if (!(EventName in handle)) {
console.error(EventName, '事件名不存在');
return;
};
// 存在則執行事件管理中的所有事件
// for和foreach的區別:for可以退出可以跳過但是foreach不行;
handle[EventName].forEach(elm => {
// 執行
elm();
});
};
使用
```js //宣告事件
function fn1() { console.log('自定義事件1'); } function fn2() { console.log('自定義事件2'); }; // 新增事件 addEvent('myevent', fn2); addEvent('myevent', fn1); //刪除事件 removeEvent('myevent', fn1); //執行事件 btn.addEventListener('click', () => { triggerEvent('myevent'); }); ```
看到程式碼想必大家明白了個大概,下面貼出完整程式碼
```js // 事件 function fn1() { console.log('自定義事件1'); }
function fn2() {
console.log('自定義事件2');
};
// 事件池
const handle = {};
// 新增事件
function addEvent(EventName, fn) {
if (!(EventName in handle)) {
handle[EventName] = [];
};
handle[EventName].push(fn);
};
// 執行函式
function triggerEvent(EventName) {
if (!(EventName in handle)) return;
handle[EventName].forEach(elm => {
elm();
});
};
// 刪除事件
function removeEvent(EventName, fn) {
if (!(EventName in handle)) return;
let i = handle[EventName].findIndex(val => {
return val == fn;
});
if (i == -1) return;
handle[EventName].splice(i, 1);
};
// 新增
addEvent('myevent', fn2);
addEvent('myevent', fn1);
// 刪除
removeEvent('myevent', fn1);
// 執行
btn.addEventListener('click', () => {
triggerEvent('myevent');
});
```
ES6實現方式
現在es6已經基本全面普及,怎麼可能我們每天都會用到的es6方案呢,強烈推薦es6方案,es6方案比es5看起來更具有結構化,看起來更為清晰這裡直接貼程式碼,思路基本都一樣的
```js
// 類
class MyEvent {
constructor() {
// 事件池
this.halder = {}
}
/
新增自定義事件
* 自定義事件管理名
* 事件名
/
addEvent(EventName, fn) {
// 判斷當前的事件管理是不是為空
if (typeof this.halder[EventName] === 'undefined') {
this.halder[EventName] = [];
};
// 把事件追加進去事件管理名
this.halder[EventName].push(fn);
}
/
刪除自定義事件
* EventName 自定義事件管理名
* fn 事件名
/
removeEvent(EventName, fn) {
// 判斷當前的事件管理是不是為空
if (!(EventName in this.halder)) return;
// 找到當前的事件在事件名中的下標並返回,沒有返回-1
let i = this.halder[EventName].findIndex(v => {
return v == fn;
});
if (i === '-1') return;
// 刪除事件,對元素組進行操作的
this.halder[EventName].splice(i, 1);
}
/*
* 執行自定義事件
* EventName 自定義事件管理名
/
tgigerEvent(EventName) {
// 判斷當前的事件管理是不是為空
if (!(EventName in this.halder))return;
this.halder[EventName].forEach(v => v());
}
};
// 建立函式
function fn1() {
console.log('事件管理1');
}
function fn2() {
console.log('事件管理2');
}
// 建立例項化物件
let obj = new MyEvent();
// 新增
obj.addEvent('my', fn1);
obj.addEvent('my', fn2);
// 刪除
obj.removeEvent('my', fn2);
// 執行
btn.addEventListener('click', () => {
obj.tgigerEvent('my');
});
```