[Vue] Vue Router 的使用技巧

[Vue] Vue Router 的使用技巧

·

1 min read

vue项目中,vue-router应该是必备的;我虽然使用了很多次,但其实对vue-router还是一知半解,今天就写一篇博客来总结一下

获取 route 对象

<script setup>中,使用useRoute()来获取route对象:

const route = useRoute()

route对象是全局单例的,在任何组件中都可以获取唯一的route对象;拿到route对象后,可以通过route来获取非常多的参数和值,route对象上的属性都是针对整个项目的浏览器url的,在任何组件中都可以使用

  • route.path获取当前url的路径,也就是你浏览器地址栏的域名和端口后面的路径:
// 这里的浏览器 url 的路径就是指 "/lord-moon/fold-unfold"
https://gitee.com/lord-moon/fold-unfold
  • route.params获取当前的路由的路径参数:
// 声明的路由对象
{
    path: "/center/:id",
    component: () => import("@/views/center/index.vue"),    
}

/**
    route.params 获取的就是 :id 的值
    你可以声明多个 param,route.params 的返回值就是一个数组
*/
  • route.matched获取当前所有匹配到的路由:

route.matched会将匹配到的多层级的路由做一个扁平化,并返回一个扁平化后的数组,在实现导航面包屑功能的时候,可以使用这个API,然后直接循环渲染route.matched返回的数组就可以了

获取 router 对象

<script setup>中,使用useRouter()来获取route对象:

const router = useRouter()

router对象使用得最多的就是replacepushgo这三个导航方法了,还可以带上参数使用,具体请参考官方文档:编程式导航 | Vue Router (vuejs.org)

使用路由守卫

这里只讲用得最多的全局路由守卫router.beforeEach;首先要讲清楚一些情况:

  • beforeEach的第三个参数是可选的next,但是在vue-router的最新版本中,已经不建议使用了,所以我们在beforeEach中就默认不再使用next参数了

  • 官方文档对beforeEach的默认说明是不作任何处理的话,就会默认放行本次路由导航;所以我们在路由守卫中仅针对我们需要验证或拦截的情况作处理即可

  • 在路由守卫中return某个路由进行导航会再次触发路由守卫

使用 addRoute 动态添加路由

在一些 b 端项目中,我们常常会做一些角色权限验证,这时候就可能需要为不同的角色动态地展示路由

那么我们在什么时候使用addRoute是正确的呢?如果我们在登录后使用addRoute的话,你刷新页面之后就会空白了,因为你的routes数组又重置为原本最初的样子了

所以我们应该统一地做addRoute操作,那么最佳的选择就是在路由守卫beforeEach中来动态地添加路由了:

router.beforeEach(async (to) => {
    const isLogin  = await checkoutLogin()
    if(isLogin) router.addRoute(<路由名称>, <路由对象>)
})

但是这样你还是会发现导航到的页面还是空白的,因为你是在路由守卫里面addRoute的,所以此时你的router对象还没有你添加的路由,你要等添加了之后,再重定向触发一次导航守卫才可以:

router.beforeEach(async (to) => {
    const isLogin  = await checkoutLogin()
    if(isLogin) {
        router.addRoute(<路由名称>, <路由对象>)
        // 重定向重新触发路由守卫
        return to.path
    } 
})

但是这样子还不够完善,因为你导航每次都会触发路由守卫,会多次添加动态路由,所以我们需要用一个标记来判断是否是第一次添加,后续就不再添加动态路由了:

const flag = true
​
router.beforeEach(async (to) => {
    const isLogin  = await checkoutLogin()
    // 使用标记判断,仅在首次的时候添加
    if(flag && isLogin) {
        router.addRoute(<路由名称>, <路由对象>)
        // 重定向重新触发路由守卫
        return to.path
    } 
})

这样子其实就差不多了,但还有需要注意的一点:动态地addRoute一般需要后端返回不同角色的路由表,然后我们再添加

如果前后端不是这样设计的话,那么我建议前端直接将所有路由写为静态的,然后统一在beforeEach中拦截即可,然后让后端接口做个权限校验就好了;因为如果不是后端动态返回的话,那么当角色多的时候,就不好维护了