Skip to content
On this page

Vue路由进阶

学习目标

  • 【掌握】路由导航守卫
  • 【掌握】路由元信息
  • 【掌握】嵌套路由
  • 【了解】路由滚动行为
  • 【掌握】路由懒加载
  • 【掌握】动态路由

之前我们学了路由基础,但Vue-router还给我们提供了更强大的功能,这些进阶内容同样有很广泛的使用场景,我们同样需要熟练掌握。

1.路由导航守卫

顾名思义,路由导航守卫可以让每个页面完成跳转前后进行一些逻辑实现。vue-router提供了多种导航守卫:全局的,单个路由独享的,或者组件级的。现在来逐一说明。

1.1 全局前置守卫

你可以使用 router.beforeEach 注册一个全局前置守卫,这样在匹配每个路由路径的时候都会进行一次进入前的"拦截",在某些需要验证登录状态的业务场景下应用极广。

我们仍然用示例来演示全局前置守卫的使用:

现在有3个页面,分别是登录页,首页,列表页。进入任何页面前都需要进行身份验证,必须本地存储中isLogin的字段为true时才可以进入,否则统一回到登录页。按照之前学习的内容快速完成路由信息的相关配置。

在配置完路由信息后,通过router.beforeEach 注册一个全局前置守卫,其中的守卫方法接受2个参数

  • to:表示当前导航即将进入的页面
  • from:表示当前导航即将离开的页面

前置守卫中通过返回的路由对象实现重定向。

js
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../components/Home.vue'
import Detail from '../components/Detail.vue'
import Login from '../components/Login.vue'

const router = createRouter({
 history: createWebHistory(),
 routes: [
   {
     path: '/',
     name: 'home',
     components: Home,
   },
   {
     path: '/detail',
     name: 'detail',
     components: Detail,
   },
   {
     path: '/login',
     name: 'login',
     components: Login,
   },
 ],
})
router.beforeEach((to, from) => {
 if (!localStorage.getItem('isLogin') && to.name !== 'login') {
   return {
     name: 'login',
   }
 }
})
export default router

在之前版本的路由中,还提供了第三个可选参数next,通过调用next方法也能进入到即将进入的路由页面,但新版本中不推荐这么做了。

1.2 全局后置守卫

和全局前置守卫类似,同样可以注册全局后置守卫,沿用上面的示例,在离开每个页面之前,都弹出一个提示框。

js
router.afterEach((to, from) => {
  alert('要离开此页面咯')
})

1.3 独享前置守卫

除了定义全局的路由守卫,还可以针对单个路由对象定义守卫:

js
{
  path: '/detail',
  name: 'detail',
  component: Detail,
  beforeEnter: (to, from) => {
    if (!localStorage.getItem('isLogin') && to.name !== 'login') {
      return {
        name: 'login',
      }
    }
  },
},

1.4 组件内部的路由守卫

除开在路由配置信息中定义导航守卫,你还可以在组件内部定义守卫:

  • beforeRouteEnter 进入路由前调用
  • beforeRouteUpdate 动态参数改变时调用
  • beforeRouteLeave 离开路由前调用

这些导航守卫的用法和上面的基本一直,大家可以自行验证,不再赘述。

2.路由元信息

你可以将任意信息添加到路由对象上,比如页面标题,鉴权认证等,Vue中的路由提供了一个meta字段,可以通过给每个路由对象配置meta字段来添加信息。

js
{
  path: '/',
  name: 'home',
  component: Home,
  meta: {
    title: '首页',
  },
},

在组件的生命周期中,可以将meta信息合理地调用出来。

vue
//Home中 组件挂载完毕后 将页面的标题内容改为meta中存放的信息
<script setup>
  import { onMounted } from 'vue'
  import { useRoute } from 'vue-router'
  onMounted(() => {
    document.title = useRoute().meta.title
  })
</script>

3.路由嵌套

某些复杂的组件关系存在层级更深的路由,这是可以利用路由嵌套来实现,给需要添加二级路由的路由对象添加children属性来配置二级路由,同样使用来渲染出口。

现在给Detail路由页面添加二级子路由,能够显示用户详情和头像详情,在对应的路由配置中添加children属性:

js
{
  path: '/detail',
  name: 'detail',
  component: Detail,
  meta: {
    title: '详情页',
  },
  children: [
    { path: 'users', name: 'users', component: Users },
    { path: 'profile', name: 'profile', component: Profile },
  ],
},

建立好对应的路由组件后,需要在Detail中添加二级路由的出口:

vue
<template>
  <h1>这是详情页</h1>
  <router-link to="users"> <button>用户详情页</button></router-link>
  <router-link to="profile"> <button>头像详情页</button></router-link>
  <router-view></router-view>
</template>

嵌套路由的使用规则跟一级路由保持一致,当然如果你的业务足够复杂,还可以嵌套三级,四级路由。

4.路由滚动行为

切换路由的过程中,VueRouter还提供了操作滚动条行为的方法,通过scrollBehavior方法可以在路由配置中规定滚动条行为。

js
const router = createRouter({
  history: createWebHashHistory(),
  routes: [...],
  scrollBehavior (to, from, savedPosition) {
    // return 期望滚动到哪个的位置
    return {
       top:30 //滚动到距离顶部30
   }
  }
})

5.路由懒加载

当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就会更加高效。

Vue Router 支持开箱即用的动态导入,这意味着你可以用动态导入代替静态导入:

js
const Detail = () => import('../components/Detail.vue')

const router = createRouter({
  // ...
  routes: [{ path: '/detail',name:'detail', component: Detail }],
})

一般来说,除开首页对所有的路由都使用动态导入是个好主意,可以将之前的路由配置都做对应的修改。

6.动态路由

对路由的添加通常是通过 配置routes来完成的,但是在某些情况下,你可能想在应用程序已经运行的时候添加或删除路由。例如在处理一些路由权限的场景下就需要动态增加路由。

6.1 增加路由

动态增加路由主要依靠router.addRoute()方法实现,获取到router实例后,可以在合理时机注册新的路由对象,

例如在登陆后新增一个Vip路由:

js
const login = () => {
    localStorage.setItem('isLogin', true)
    isVip.value = true
    router.addRoute({
      path: '/vip',
      name: 'vip',
      component: Vip,
    })
}

6.2 删除路由

动态删除路由最常用的方法是通过使用 router.removeRoute() 按名称删除路由,所以注册路由信息时添加name属性是一个好习惯,大家务必养成。

我们示例中登录退出希望将Vip路由删除掉:

js
const out = () => {
    localStorage.clear()
    isVip.value = false
    router.removeRoute('vip')
  }

最终Login组件的页面代码会显得比较丰富完整,应该是这样的:

vue
<template>
  <router-link to="/"><button>首页</button></router-link>
  <router-link to="/detail"><button>详情页</button></router-link>
  <router-link to="/vip" v-if="isVip"><button>Vip页</button></router-link>
  <button @click="login">登录</button>
  <button @click="out">退出登录</button>
</template>

<script setup>
  import { ref } from 'vue'
  import { useRouter } from 'vue-router'
  import Vip from '../components/Vip.vue'
  const router = useRouter()
  const login = () => {
    localStorage.setItem('isLogin', true)
    isVip.value = true
    router.addRoute({
      path: '/vip',
      name: 'vip',
      component: Vip,
    })
  }
  const out = () => {
    localStorage.clear()
    isVip.value = false
     router.removeRoute('vip')
  }
  let isVip = ref(localStorage.getItem('isLogin'))
</script>

<style></style>

6.3 查看当前路由

Vue Router 提供了两个功能来查看现有的路由:

  • router.hasRoute():检查路由是否存在。
  • router.getRoutes():获取一个包含所有路由记录的数组。

版权声明 鄂ICP备2022000216号-2