为了在异步组件加载过程中显示加载中状态,引入了 LazyLoadView,但这种方案直接导致了组件内的导航守卫 beforeRouteEnter/beforeRouteLeave
失效,下面就是该问题的一种尝试解决方案:
创建 eventbus
1 2 3 4 5 6
| import Vue from 'vue'
const eventbus = new Vue()
export default eventbus
|
为了方便使用,我们将 eventbus
注册在 Vue
的原型上
1 2 3 4
| import Vue from 'vue' import eventbus from '@/utils/eventbus' Vue.prototype.$eventbus = eventbus
|
自定义导航守卫(也就是自定义事件)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
|
import eventbus from '@/utils/eventbus'
const routeEnterList = ['RouteA', 'RouteB'] const beforeRouteEnter = {}
routeEnterList.forEach(route => { beforeRouteEnter[route] = (to, from) => { eventbus.$emit(`before${route}Enter`, to, from) } })
const routeLeaveList = ['RouteC', 'RouteD', 'RouteE'] const beforeRouteLeave = {}
routeLeaveList.forEach(route => { beforeRouteLeave[route] = (to, from, next) => { eventbus.$emit(`before${route}Leave`, to, from, next) } })
export { beforeRouteEnter, beforeRouteLeave }
|
我们把需要使用组件内导航守卫 beforeRouteEnter
和 beforeRouteLeave
的组件名(路由名与组件名一致,可以通过此脚本检测)分别添加到上面文件对应的数组 routeEnterList
和 routeLeaveList
中
通过全局守卫触发事件,模拟组件内导航守卫
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import Vue from 'vue' import router from './router' import { beforeRouteEnter, beforeRouteLeave } from '@/routeGuard'
router.beforeResolve((to, from, next) => { if (beforeRouteLeave[from.name]) { return beforeRouteLeave[from.name](to, from, next) } next() })
router.afterEach((to, from) => { Vue.prototype.$beforeRouteEnterParams = { to, from } if (beforeRouteEnter[to.name]) { beforeRouteEnter[to.name](to, from) } })
|
组件内部监听相应的事件,模拟组件内导航守卫
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| <script> // ...
export default { // ... created() { // ! 先存储当前路由名(beforeDestroy 钩子中 this.$route 可能已经变了) this._name = this.$route.name
// 这些不放在 beforeCreate 中的原因在于 beforeCreate 中还拿不到 methods 中的方法 // 类似 addEventlistioner 和 removeEventListioner,on 和 off 的回调函数必须是同一个 this.$eventbus.$off(`before${this._name}Enter`, this.beforeRouteEnter) this.$eventbus.$on(`before${this._name}Enter`, this.beforeRouteEnter) this.$eventbus.$off(`before${this._name}Leave`, this.beforeRouteLeave) this.$eventbus.$on(`before${this._name}Leave`, this.beforeRouteLeave)
// 由于全局守卫 afterEach 会先于组件的 created 执行,导致第一次未触发 // `before${this.$route.name}Enter` 事件,这里手动触发一下, // this.$beforeRouteEnterParams 是在全局守卫 afterEach 中记录的 to 和 from // ! 注意:this.beforeRouteEnter 中有依赖数据初始化的,初始化逻辑需在此之前 this.$eventbus.$emit(`before${this._name}Enter`, this.$beforeRouteEnterParams.to, this.$beforeRouteEnterParams.from) // ... }, beforeDestroy() { // ! 这里不用 this.$route.name 是因为销毁前路由可能已经改变 this.$eventbus.$off(`before${this._name}Enter`, this.beforeRouteEnter) this.$eventbus.$off(`before${this._name}Leave`, this.beforeRouteLeave) // ... }, methods: { // 模拟的 beforeRouteEnter beforeRouteEnter(to, from) { // ... }, // 模拟的 beforeRouteLeave beforeRouteLeave(to, from, next) { // ... // 记得执行 next() } } // ... } </script>
|