我正在参加「初夏创意投稿大赛」详情请看:初夏创意投稿大赛
炎炎夏日 ,今天你学习了吗?
当我们拥有一堆代码,且看不懂的时候,这个时候我们就该想该如何去重构该代码,此时我们就可以采用自定义事件管理的方式,能够更好的管理维护代码,这个时候就会发起疑问了,为什么要采用这种方式呢,个人认为自定义事件管理有以下优点:
- 占用内存小,项目启动快,能够很好的提高性能
- 减少事件注册,不会覆盖掉之前的相同事件
他的缺点也很明显,因为它不会覆盖掉之前相同的事件,就极有可能会出现事件混乱运行的情况,这里需要注意一下
如何实现自定义事件管理
自定义事件管理,实现的方法有很多,我这里讲俩种方案,思路都是基本一样,自定义事件管理是把所有事件放到一个地方统一管理,可以进行删除,添加,触发,存储事件的地方叫做事件池,事件池存放了所有触发元素和事件;
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');
});