在架构升级过程中,我们不但要保证重构后新代码完全符合设计规范,还要保证老代码能正常运行,同时兼容原来的事件通知。但老代码的事件通知可能有 eventbus、vuex 等等实现方式,在新的架构下,我们将逐步淘汰这种通信方式。要实现新老代码顺利过渡,请大家参考如下示例迁移代码。
迁移 eventBus
原业务组件代码:
export default {
mounted() {
this.$eventBus.$on('userLogin', this.login)
},
beforeDestory() {
this.$eventBus.$off('userLogin', this.login)
},
methods: {
logout() {
this.$eventBus.$emit('userLogout')
},
login() {
console.log('用户登录成功了')
}
}
}
通过分析以上代码的两个事件,我们可以把两个事件均归类为用户消息通知。我们可以在 UserSerivce 中来桥接原来的事件。 如果还有其它事件,我们需要以业务类型,如支付消息,我们就需要在 PayService 里做桥接。总之,我们需要把所有的数据通讯归类到具体的业务类型。后续的开发的服务、组件或重构的组件均通过相关桥接服务访问原来的事件。从而达到逐步替换原来设计,并最终取代。 我们需要先用一个类作为依赖注入的 eventBus
@Injectable()
export class EventBusService extends Vue {}
export const eventBus = new EventBusService()
然后我们把 EventBusService 在根组件或 App 实例提供(根据 vue 版本不同而不同),以 vue2 为例
// # main.ts
Vue.prototype.$eventBus = eventBus
// # App.vue
export default defineComponent({
setup() {
// 在根组件容器内提供 eventBus 桥接类,以供所有其它组件和服务访问
useRootReflectiveInjector([{
provide: EventBusService,
useValue: eventBus
},
UserService
])
}
})
重构后的消息通知类
@Injectable()
export class UserService {
onLogin = new Subject<void>()
onLogout = new Subject<void>()
// 当项目内再也没有组件通过 eventBus 依赖这两个事件时,下面的桥接代码就可以删除了
// 桥接代码 start...
constructor(private eventBus: EventBusService) {
let isLoginFromSelf = false
let isLogoutFromSelf = false
eventBus.$on('userLogin', () => {
isLoginFromSelf = true
this.onLogin.next()
isLoginFromSelf = false
})
eventBus.$on('userLogout', () => {
isLogoutFromSelf = true
this.onLogout.next()
isLogoutFromSelf = false
})
this.onLogin.subscribe(() => {
if (isLoginFromSelf) {
return
}
eventBus.$emit('userLogin')
})
this.onLogout.subscribe(() => {
if (isLogoutFromSelf) {
return
}
eventBus.$emit('userLogout')
})
}
// 桥接代码 end...
}
在上面代码中,我们用 Subject 类作为新的事件分发器。同时我们用了两个变量 isLoginFromSlef、isLogoutFromSelf 来作为状态机,防止事件分发进入死循环。在做桥接时,尤其要注意死循环!
有了桥接服务后,我们来正式重构我们的组件代码。
export default defineComponent({
setup() {
const injector = useReflectiveInjector()
const user = injector.get(UserService)
function logout() {
user.onLogout.next()
}
const subs = []
onMounted(() => {
subs.push(
user.onLogin.subscribe(() => {
console.log('用户登录成功了')
})
)
})
onUnmounted(() => {
subs.forEach(i => i.unsubscribe())
})
}
})
我们可以按上面的方法迁移其它的事件通知,当所有原来的依赖迁移完成后,就可以把 EventBusService 和原来的 eventBus 删除了。