阴间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: truename: 'home' 之类的选项以及任何用在 router-linkto proprouter.push 中的选项。
    • next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。

确保 next 函数在任何给定的导航守卫中都被严格调用一次。它可以出现多于一次,但是只能在所有的逻辑路径都不重叠的情况下,否则钩子永远都不会被解析或报错

——导航守卫 | Vue Router (vuejs.org)

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:一个是用来获取路由信息的
router

route

人生到处知何似,应似飞鸿踏雪泥。
原文地址:https://www.cnblogs.com/lepanyou/p/15701494.html