• 阴间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

    人生到处知何似,应似飞鸿踏雪泥。
  • 相关阅读:
    freopen stdout 真的更快?
    【评分】第二次作业——个人项目实战
    【评分】第二次作业-数独-第一次测试成绩
    姑娘你大胆地往前走——答大二学生XCL之八问
    第二次作业-数独-初步测试日志
    第二次作业——个人项目实战
    关于C#的随机数
    必须展示窗口才能截图怎么办,伪后台截图思路
    Winform 奇怪的 英文字体错乱显示问题
    wpf 解决 WPF SelectionChanged事件向上传递造成重复执行不想执行的函数的问题
  • 原文地址:https://www.cnblogs.com/lepanyou/p/15701494.html
Copyright © 2020-2023  润新知