Event事件解耦
709字约2分钟
2024-08-20
事件解耦
其实主要的就是降低各个模块之间耦合度,减少改模块牵动一堆东西。ps:这里主要用发布订阅的模式进行解耦。
思路
- 可以将事件模块化,各个模块管理自己的事情
- 同一个事件,有可能会有多个逻辑触发
- 后期维护也只需要维护事件的新增等问题,不需要改动其他模块。
代码实现
- 建议分多个模块,一个模块处理多个事件后期维护有点麻烦。
- 不同模块事件中心,处理不同模块事件。
// 1. 定义一个事件名称数组
const EventName = ['API:GET', 'API:POST'] as const
// 2.将所有事件转换成枚举
type EventList = (typeof EventName)[number]
export default class EventListener {
// 3. 定义一个事件对象,key为事件名称,value为回调函数数组
private events: Record<EventList, Set<Function>> = {
// 登录事件
'API:LOGIN': new Set(),
// 登出事件
'API:LOGOUT': new Set(),
}
// 4. 监听事件
on(event: EventList, listener: Function) {
this.events[event].add(listener)
}
// 5. 触发事件
emit(event: EventList, ...args: any[]) {
this.events[event].forEach(listener => listener(...args))
}
}
实际场景使用
- 当前假设 已经在全局注册了事件中心,并且已经引入了事件中心。并在axios中中使用了拦截器,拦截器中触发事件。
// axios.ts 中
// 响应拦截中
server.interceptors.response.use(
(res: any) => {
let { data,status } = res;
if(status === 301){
// 登出事件需要做两件事清除store 和 跳转到login页面
// 一般写法肯定是引入路由写登出逻辑,但是如果不同的状态码,处理的逻辑不同,耦合度就太高了。
// 这里使用发布订阅解耦后就不用做任何处理,剩下的交给router.ts和store.ts处理事件
EventListener.emit('API:LOGOUT')
}
return Promise.resolve(data)
},
(error: Error) => {
console.log('响应失败', error)
return Promise.resolve(error)
}
)
- 路由需要跳转login页面
// router.ts 中
// 创建路由的文件示例
import { createRouter, createWebHistory, createWebHashHistory } from 'vue-router'
import routes from './routes'
const router = createRouter({
history: createWebHashHistory(),
routes
})
// 监听事件
EventListener.on('API:LOGOUT', () => {
router.push('/login')
})
export default router;
- 清理store
// 监听事件
EventListener.on('API:LOGOUT', () => {
// 清除逻辑,可能还有更多逻辑
localStorer.clear()
sessionStore.clear()
....
})
总结
- 现在其实可以发现,这种写法减少了axios请求拦截的处理逻辑,也降低了各个模块之间的耦合度。
- 各司其职,避免开发或者后期维护,改动更多模块。
- 建议使用TS来完成,拥有类型提示,可以在开发中更加清楚事件作用。
- 如果事件很多的话建议:一定要模块化,不要把所有事件都放在一个文件中,这样后期维护起来比较麻烦。
- 大型项目还是用中间件实现吧,支持更好。