阴间BUG之动态路由刷新几率回首页
0. 缘起
有个动态路由,根据后台传来的路由信息存vuex生成对应路由,然后因为在router.js里有一处根据静态界面数量判断是否刷新和1个后加的需求刷新改变某动态界面样式即时可查看,这网页就变得很灵异了。几率刷新界面跳转回登录页或者/tfw一个静态页面,我团队的小伙伴都苦不堪言,我也极其痛苦。
1. VueRouter
API 参考 | Vue Router (vuejs.org)
Vue动态路由配置-router.addRoute - 葬月! - 博客园 (cnblogs.com)
2. 流程
后台发过来1堆布局,前端放到VueX里面,配合VueX-persistedstate插件可持续化存储,再通过。每次刷新页面都会重复这一步操作。
// /store/index.js
// addRoute
async addRoutes({state, commit}, deliver) {
let res = await getWebUiConfig(deliver);
if (res && res.success) {
let configures = state.version === 1 ? res.data : res.data.firstMenuList;
let routers = convertConfigToLayout(configures, state.version);
router.addRoutes(asyncRouters(routers))
commit("SET_ROUTERS", routers);
}
},
async updateRouters({state, commit, dispatch}) {
let deliver = {classifyId: state.classifyId, platform: 3};
let res = await getWebUiConfig(deliver);
if (res && res.success) {
let configures = state.version === 1 ? res.data : res.data.firstMenuList;
let routers = convertConfigToLayout(configures, state.version);
resetRouter();
commit("SET_ROUTERS", routers);
dispatch("generateRouters");
}
},
async generateRouters({state}) {
router.addRoutes(asyncRouters(state.routers));
}
// /utils/utils.js
// 异步路由加载
export function asyncRouters(routers) {
return routers.map(item => {
return {
path: `/${item.router}`,
name: item.router.toUpperCase(),
component: () => import('../views/Home'),
meta: {
alias: item.alias // 路由名称
},
}
})
}
// 动态路由添加 + 权限验证
router.beforeEach((to, from, next) => {
if (to.path === "/" || to.path === "/login" || to.path === "/config") {
next()
} else if (sessionStorage.getItem('token')) {
// getRoutes: get the latest router info
let constRoutes = router.getRoutes().filter(item => item.meta.constant);
if (store.state.routers.length > 0 && router.getRoutes().length === constRoutes.length) {
store.dispatch("generateRouters").then(() => {
next(to.path);
})
} else {
next();
}
} else {
next('/login');
}
})
如果这个路由最近浏览的界面,只有静态界面,就再获取一次动态路由,获得最新信息。
需要注意的是,现在addRoutes已经被addRoute取代了,虽然还能用,但是会报黄警告,丑陋!
3. BUG出现点
由于是动态布局,每次改变布局样式,需要刷新后可见最新样式,但是一刷新就会回到登录页。原因是,我获取最新布局的方法如下
// Refresh Page
refreshPage() {
// console.log("this.router", this.$route);
// let needRefreshPath = this.$store.state.routers.map(
// (item) => "/" + item.router
// );
// console.log("needRefreshPath : ", needRefreshPath);
// if (needRefreshPath.includes(this.$route.path)) {
let deliver = {
platform: 3,
classifyId: this.$store.state.enterprise.classifyDeviceId,
};
this.$store.dispatch("addRoutes", deliver).then(() => {
if (this.routers.length) {
this.$router.push(this.$router.currentRoute.path);
} else {
this.$router.push("/tfw");
}
});
// }
},
这里BUG的表现形式是,刷新网页,页面卡顿片刻,随后路由导向至登录页,再次登录后时进入/tfw页。原因我还没整明白为什么,但重点就是动态路由的获取步骤和路由导向出现了问题。
在整个网页里路由导向至/tfw的只有首页没有动态路由的情况,所以必然是前者的获取有问题。而且只有刷新会带来BUG,那就是这个刷新方法的问题。
this.routers是动态路由的获取,当this.routers长度为零时才会导向/tfw。
next: Function
: 一定要调用该方法来 resolve 这个钩子。执行效果依赖next
方法的调用参数。
next()
: 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。next(false)
: 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到from
路由对应的地址。next('/')
或者next({ path: '/' })
: 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向next
传递任意位置对象,且允许设置诸如replace: true
、name: 'home'
之类的选项以及任何用在router-link
的to
prop 或router.push
中的选项。next(error)
: (2.4.0+) 如果传入next
的参数是一个Error
实例,则导航会被终止且该错误会被传递给router.onError()
注册过的回调。确保
next
函数在任何给定的导航守卫中都被严格调用一次。它可以出现多于一次,但是只能在所有的逻辑路径都不重叠的情况下,否则钩子永远都不会被解析或报错。
next( ) 与next (有参)的异同
因为每次跳转到一个路由的时候都会 触发 全局守卫 由于判断条件未改变 所以 一直循环,无法正常跳转。因此如果要跳转到指定页,需要在全局守卫钩子里注意,是否会有造成无限循环的情况。最直白的解法是判断to.path是否为next参数值,不是就不会造成循环。
4. 组长の观点
由于本人辣鸡水平,并没有看出哪里的问题。组长看了圈后,他亲自出马解决了。大致就是刷新浏览器的时候清缓存了,导致既没有获取动态路由,又跳转到了错误的页面。所以,重要的就是,得再DOM加载完成之后再获取。
window.onload = () => {
this.$store.dispatch("updateRouters");
}
5. 弊端
以上写法有个遗落点,会导致不同动态路由地址的时候有卡死循环的BUG。
解决方法:https://www.cnblogs.com/lepanyou/p/15710078.html
6. router与route
router:一个是用来操作路由的$route$router
route:一个是用来获取路由信息的