正值初夏,瞭解一下JavaScript事件管理

語言: CN / TW / HK

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');
    });

```