vue添加路由和页面为什么不显示(vue页面路由配置和使用)

前言

项目框架:Vue3 + TypeScript

有这样一个需求,系统默认只有最基础的几个路由,如登录、404等,其它路由需要在登录后动态添加。系统没有固定首页,登录完成后跳转至动态菜单的第一个菜单页。

分析

这一逻辑乍一看很简单,其实有很多小坑在里面。其中最容易踩的的坑是动态路由尚未渲染完成就已经触发路由跳转了,这时候肯定是404,因为路由并不存在;另一个容易踩的坑是路由重复加载,此时页面会显示空白,需要手动刷新才能正常显示。

首先想到的就是使用 Promise 函数解决,结果行不通。addRoute 是一个宏任务 和 resolve 是微任务,所以 Promise 结束的时候并不能代表动态路由已经添加完成。

其次又想到使用 async 函数来确保获取到登录成功结果的时候,路由已经添加完成,结果一番尝试后依然行不通。因为添加路由的操作不是异步的,没有返回 Promise 对象,因此这里的 awt 是不会产生效果的。(PS:事后使用 Promise.all 解决了这一问题,后面的具体方法上会说。)

最后,想到了一个很笨的解决方法,轮询。实验过后,确定可以实现,但就如开头说的,这会显得很 low ,虽然它最终解决了问题。

实践

登录的操作都是一样的,所以单独拿出来只写一遍。表单就不做介绍了,就从点击登录表单校验通过后说起。

所有登录的代码放到一个页面会显得臃肿,所以具体登录的操作逻辑我把它抽离了出来。在 src/utils 目录下创建一个 auth.ts 文件。

auth.ts

ts复制代码import { useRouteListStore } from '@/store/router'  const routeListStore = useRouteListStore()    // 登录  export async function Login(data: { username: string; password: string; portal: string; corpCode: string }) {    const { username, password, portal, corpCode } = data    try {      // 登录接口      const res = await getLogin({ username, password, portal, corpCode })      // ...      // 这里写保存用户信息及 token 的逻辑      // ...            // 添加路由操作,写在 pinia 中,后面会说      await routeListStore.updateRouteList()      return res    } catch (err) {      return err    }  }  

接下来要写添加路由的具体逻辑。在 src/store 目录下创建一个 router.ts 文件,添加内容如下:(PS:具体文件路径要结合具体的项目内容,以下路径及菜单格式仅作为示例)。

根据处理方式不同,有两种方案。

方案一:使用 async 函数

src/store/router.ts

ts复制代码export const useRouteListStore = defineStore('routeList', {    state: () => ({      routeList: [],      breadcrumb: [],      getRouter: true // 是否需要重新加载路由    }),    actions: {      // 更新菜单并追加路由      async updateRouteList() {        const modules = import.meta.glob('../views/**/*.vue')        // 此为接口请求获取的菜单        const list = await getMenus()        list.forEach((e) => {          e.route = e.path          e.component = () => import('@/layout/index.vue')          e.redirect = `${e.path}/${e.children[0].path}`          e.children.forEach((item) => {            item.route = `${e.path}/${item.path}`            item.component = modules[`../views${item.component}.vue`]          })        })        await addRouteList(list)        this.getRouter = false        this.routeList = list        return true      },    }  })  

接下来写动态添加路由的逻辑,使用 Promise.all 来确保 Pinia 中返回结果时,动态路由已经加载完成。在 src/router 创建 index.ts 文件,添加内容如下:

src/router/index.ts

ts复制代码export function addRouteList(data: any[] = []) {    return new Promise((resolve) => {      const promises = []      data.forEach((e) => promises.push(router.addRoute(e)))      Promise.all(promises).then(() => resolve(true))    })  }  

使用 async 函数之后,登录页的操作将会变得很简单。

login.vue

ts复制代码import { Login } from '@/utils/auth'    const onSubmit = () => {    validate().then(() => {      Login(formState).then(() => {        router.push(routerStore.routeList[0].path)      }).catch(err => {        message.error(err.message)      })    })  }  

方案二:使用轮询

轮询的方案相比于使用 async 函数要简单很多,因为它不需要确保登录后拿到结果的那一刻,路由是加载完成的。具体实现代码如下:

src/store/router.ts

ts复制代码export const useRouteListStore = defineStore('routeList', {    state: () => ({      routeList: [],      breadcrumb: [],      getRouter: true    }),    actions: {      // 更新菜单并追加路由      updateRouteList() {        listMenus().then((res) => {          const list = res.data          if (list === null) {            this.getRouter = false            router.push('/404')            return          }          list.forEach((e) => {            e.route = e.path            e.component = () => import('@/layout/index.vue')            e.children.forEach((item) => {              item.route = `${e.path}/${item.path}`              item.component = modules[`../views${item.component}.vue`]            })          })          addRouteList(list)          this.getRouter = false          this.routeList = list        })    }  })  

src/router/index.ts

ts复制代码export function addRouteList(data: any[] = []) {    data.forEach((e) => {      router.addRoute(e)    })  }  

轮询的好处是逻辑简单,唯一麻烦的一点就是在登录后添加一个定时器去定期获取路由是否加载完成。之所以要加定时器是因为获取菜单是异步请求,而程序执行时很快的,所以要确保执行路由跳转命令时菜单是加载完成的。

login.vue

ts复制代码import { ref, onBeforeUnmount } from 'vue'  import { useRouter } from 'vue-router'  import { useRouteListStore } from '@/store/router'  const routerStore = useRouteListStore()  import { Login } from '@/utils/auth'  const router = useRouter()    // 每0.5s判断一次菜单是否加载完成,最多判断30次,超过则说明网络环境极差  const timer = ref(null)  const onSubmit = () => {    validate().then(() => {      Login(formState).then(() => {      let i = 0        timer.value = setInterval(() => {          if (routerStore.routeList[0].path) {            router.push(routerStore.routeList[0].path)          }          i++          if (i > 30) {            clearInterval(timer.value)            timer.value = null            i = null            message.error('当前网络环境较差!')            spinning.value = false          }        }, 500)      })    })  }    // 不要忘记清除定时器  onBeforeUnmount(() => {    clearInterval(timer.value)    timer.value = null  })  

补充

以上代码只能保证系统初次登录后可以正常跳转页面,如果退出当前账号,重新登录或者更换账号登录,会出现路由重复加载的问题,也就是文章开头所说的另一个容易踩的坑。这个坑解决起来并不困难,只要注意到了,很容易就可以解决。

解决思路是添加路由前置守卫,同时在 Pinia 中添加一个字段判断当前路由是否需要重新加载即可。具体代码如下:

js复制代码import Cookies from 'js-cookie'  import { useRouteListStore } from '@/store/router'    // 前置守卫  router.beforeEach(async (to, from, next) => {    const token = Cookies.get('token')    if (!token) {      next({ path: '/login' })    } else {      const routerStore = useRouteListStore()      routerStore.addBreadcrumb(to)            // 判断菜单是否存在且是否需要重新加载      if (routerStore.routeList.length === 0 && routerStore.getRouter) {        await routerStore.updateRouteList()        next({ path: to.path, query: to.query })      } else {        next()      }    }  })  

如对本文有疑问或不同看法,欢迎在评论区指出。

感谢您访问:美文云网站!本文永久链接:https://meiwenyun.com/433286.html。侵删或不良信息举报请联系邮箱:820608633@qq.com或微信:meiwenyun888。
上一篇 2024年8月23日 05:08
下一篇 2024年8月23日 05:08

相关推荐

  • 霜降北方地区冷吗 霜降穿什么衣服

    2018年霜降是几月几号几点 霜降的意思是什么 白天 霜降节气,秋天向冬天过渡。温度较之前的节气有了明显的降低,霜降节气时白天的温度普遍在18℃左右。 衣着建议 可以穿单层衣服。例…

    2024年8月3日
    137
  • 《尚食》强势精明的张皇后为何会输给了郭贵妃

    《尚食》强势精明的张皇后为何会输给了郭贵妃 吴谨言这次解锁的新角色是姚子衿,她是出身良好的民间少女,喜欢绘画烹饪鼓琴,少年时曾偶遇随朱棣暗访农家的朱瞻基,从此对他一见钟情;许凯饰演…

    2024年8月9日
    134
  • 圆珠笔弄到皮革上面如何去除 圆珠笔弄到皮革上面怎么去除

    1、我们可以用酒精去印迹 因为圆珠笔水会和酒精发生化学反应,溶于酒精。所以用毛巾蘸上少许稀释的酒精轻轻抹 去污渍,再用湿布擦去残留的酒精,然后用干毛巾擦干表面的水分,等到风干之后用…

    2024年8月9日
    110
  • 鱼池水质测试技术

    鱼池水质管理,直接影响养鱼效益。衡量鱼池水质好坏的指标主要有:池水温度、酸碱度(pH值)、溶氧值和透明度。现将其测试技术简介如下:   1.温度测试不同鱼类对水温的要求不同。鲢、鳙…

    2022年12月30日
    261
  • 支付宝会员日是有什么用 支付宝会员日是几号

    支付宝会员日是每月20日。支付宝会员能享受生活助手服务。生活助手服务包括:担保交易付款、信用卡还款、缴交水电煤费、缴纳通讯费、送礼金和AA收款等。支付宝会员等级包括2个等级,分别为…

    2024年8月12日
    148
  • 春节前立春暖和吗 立春就暖和了吗

    衣服淋雨了要怎么处理 雨水淋过的衣服能穿吗 立春就暖和了吗 不一定。 立春节气是一个表示春季开始的节气,此时节开始,天气有了变暖和的迹象,万物一派生机勃勃的样子,但是过了立春还要冷…

    2024年8月12日
    161
分享本页
返回顶部