在架构升级过程中,我们不但要保证重构后新代码完全符合设计规范,还要保证老代码能正常运行,同时兼容原来的事件通知。但老代码的事件通知可能有 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.tsVue.prototype.$eventBus = eventBus
// # App.vueexport 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 = falselet isLogoutFromSelf = falseeventBus.$on('userLogin', () => {isLoginFromSelf = truethis.onLogin.next()isLoginFromSelf = false})eventBus.$on('userLogout', () => {isLogoutFromSelf = truethis.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 删除了。
