qiankun-vue3路由问题

5,895 阅读3分钟

遇到的问题:当子应用切换过一次路由后,主应用切换路由会报错

项目信息

gitee.com/baizhua/qia…

主应用:

使用Vue CLI 4 搭建(ts、3.x、router、history)

"qiankun": "^2.4.0",
"vue": "^3.0.0",
"vue-router": "^4.0.0-0"

关键代码如下 main.ts

App.vue

router/index.ts

子应用:

使用Vue CLI 4 搭建(2.x、router、hash)

"vue": "^2.6.11",
"vue-router": "^3.2.0"

关键代码如下 main.js

问题描述

当子应用切换过一次路由后,主应用路由报错

试过子应用使用vue3 & hash路由,能正常使用(但其实也存在问题,主应用的history.state还是被子应用修改了,只是数据结构和主应用一致所以未报错。子应用使用vue3 & history,添加base可以完美使用)。总的来说问题是主应用和子应用使用不同版本的vue(vue-router)造成的。

查看官方文档、仓库issues和搜索谷歌均未找到合适的解决方案。

操作步骤
  1. 点击子应用对应的路由(app-sub-vue2)
  2. 点击子应用的其他路由(About)
  3. 点击主应用其他路由(Home)

现在的解决方案

  • 在子应用里修改:在子应用切换路由后手动调用一次window.history.pushState(null,'',''),调用后主应用路由可正常使用
  • 在主应用修改:通过router.beforeEach判断history.state数据结构是否异常,若异常则重新设置
分析

通过debugger找到报错位置为主应用的vue-router 在切换主应用路由时,会调用push(vue-router/history/html5.ts)方法

在265行会先调用一次changeLocation用来记录当前路由信息(中间状态)

也就是在这一步执行的时候,在方法changeLocation(history/html5.ts)执行到history.replaceStatelocatin.replace(214、223)方法的时候由于url(http://localhost:6700undefined)无效而报错,从207行看出,undefined其实就是to这个入参,是从外部传入的。

正常情况下,这一步操作后这里传入的to应该为/app-sub-vue2#/about,表示当前的路由信息,但是这里传入的to成了undefined

又回到push,在调用changeLocation的时候传入的to其实是由两个变量合并而来的(247行),一个是内部变量historyState,另一个是全局对象historystate属性,然后我分别看了下这两个变量

首先看historystate属性,history是全局对象,那么在子应用切换路由的时候,很可能会改变到它的属性,经过验证,在子应用切换路由的时候也确实修改到了history.state,但是子应用应该只能修改代理的fakeWindow上的数据才对(后面发现其实不是),也就是主应用挂载到window.proxy下的数据(尝试了一下发现window.proxy.history === window.history),所以推断这里应该是主应用监听的popstate被子应用触发了

又看了下另外一个变量historyState,主应用的popstate监听函数被子应用触发后就直接给它赋值了

接下来去看了下qiankun的代码,在js沙箱相关处理的地方发现,当子应用获取history时,其实返回的就是主应用的history对象,所以它们使用的是同一个history对象,那么自然当子应用修改history信息时,主应用也会被影响到。

疑惑 上面提到的手动调用一次window.history.pushState(null,'',''),其实也是因为传入的statenull,然后在vue-router里面有做判断。但是这个处理方法需要侵入子应用的业务代码来操作,感觉不太好。

所以,主应用、子应用在操作history时,会相互影响,但是vue-router的3.x和4.x版本存储history.state的时候数据结构又不相同,那么该如何来解决这个问题呢?