我正在参加「初夏创意投稿大赛」详情请看:初夏创意投稿大赛
炎炎夏日 ,今天你学习了吗?
当我们拥有一堆代码,且看不懂的时候,这个时候我们就该想该如何去重构该代码,此时我们就可以采用自定义事件管理的方式,能够更好的管理维护代码,这个时候就会发起疑问了,为什么要采用这种方式呢,个人认为自定义事件管理有以下优点:
- 占用内存小,项目启动快,能够很好的提高性能
- 减少事件注册,不会覆盖掉之前的相同事件
他的缺点也很明显,因为它不会覆盖掉之前相同的事件,就极有可能会出现事件混乱运行的情况,这里需要注意一下
如何实现自定义事件管理
自定义事件管理,实现的方法有很多,我这里讲俩种方案,思路都是基本一样,自定义事件管理是把所有事件放到一个地方统一管理,可以进行删除,添加,触发,存储事件的地方叫做事件池,事件池存放了所有触发元素和事件;
ES5实现方式
事件池:用于管理自定义事件
//事件池 /** * 存储后的数据:key是事件管理名,val是一个数组,里面是事件 "mydom":['事件1','事件2'] **/ const handle={};
往事件池里面添加事件
/** EventName 事件管理名 fn 需要添加的事件 */ function addEvent(EventName, fn) { // 判断事件名是否存在于事件池,如果不存在则创建一个空数组 if (!(EventName in handle)) { handle[EventName] = []; }; // 添加进去 handle[EventName].push(fn); };
删除事件
/** 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); };
触发事件
/** EventName 事件管理名,用于事件名下管理的所有事件 */ function triggerEvent(EventName) { // 判断当前的事件管理名是否存在,不存在则退出 if (!(EventName in handle)) { console.error(EventName, '事件名不存在'); return; }; // 存在则执行事件管理中的所有事件 // for和foreach的区别:for可以退出可以跳过但是foreach不行; handle[EventName].forEach(elm => { // 执行 elm(); }); };
使用
//声明事件 function fn1() { console.log('自定义事件1'); } function fn2() { console.log('自定义事件2'); }; // 添加事件 addEvent('myevent', fn2); addEvent('myevent', fn1); //删除事件 removeEvent('myevent', fn1); //执行事件 btn.addEventListener('click', () => { triggerEvent('myevent'); });
看到代码想必大家明白了个大概,下面贴出完整代码
// 事件 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看起来更具有结构化,看起来更为清晰这里直接贴代码,思路基本都一样的
// 类 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'); });