Vue Router

54 阅读2分钟

1. 基本概念

Vue Router 是 Vue.js 的官方路由管理器。主要功能包括:

  • 路由模式:Hash 模式和 History 模式

  • 动态路由匹配

  • 嵌套路由

  • 导航守卫

  • 路由元信息

  • 路由懒加载

2. 基础配置和使用

// router/index.ts
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'

const routes: Array<RouteRecordRaw> = [
  {
    path: '/',
    name: 'Home',
    component: () => import('@/views/Home.vue'),
    meta: {
      title: '首页',
      requiresAuth: true
    }
  },
  {
    path: '/about/:id', // 动态路由
    name: 'About',
    component: () => import('@/views/About.vue'),
    // 嵌套路由
    children: [
      {
        path: 'profile',
        component: () => import('@/views/Profile.vue')
      }
    ]
  },
  {
    path: '/:pathMatch(.*)*', // 404 路由
    name: 'NotFound',
    component: () => import('@/views/NotFound.vue')
  }
]

const router = createRouter({
  history: createWebHistory(), // 使用 history 模式
  routes
})

export default router

3. 导航守卫

// 全局前置守卫
router.beforeEach((to, from, next) => {
  // 检查路由是否需要认证
  if (to.meta.requiresAuth && !isAuthenticated()) {
    next('/login')
  } else {
    next()
  }
})

// 全局后置守卫
router.afterEach((to, from) => {
  // 更新页面标题
  document.title = to.meta.title || 'Default Title'
})

// 路由独享守卫
{
  path: '/admin',
  component: Admin,
  beforeEnter: (to, from, next) => {
    if (isAdmin()) {
      next()
    } else {
      next('/403')
    }
  }
}

// 组件内守卫
export default {
  beforeRouteEnter(to, from, next) {
    // 在渲染该组件的对应路由被验证前调用
  },
  beforeRouteUpdate(to, from, next) {
    // 在当前路由改变,但是该组件被复用时调用
  },
  beforeRouteLeave(to, from, next) {
    // 导航离开该组件的对应路由时调用
  }
}

4. 路由跳转方法

<template>
  <!-- 声明式导航 -->
  <router-link to="/home">首页</router-link>
  <router-link :to="{ name: 'About', params: { id: 123 }}">关于</router-link>

  <!-- 编程式导航 -->
  <button @click="handleNavigate">跳转</button>
</template>

<script setup lang="ts">
import { useRouter, useRoute } from 'vue-router'

const router = useRouter()
const route = useRoute()

const handleNavigate = () => {
  // 字符串路径
  router.push('/home')

  // 对象
  router.push({
    name: 'About',
    params: { id: 123 },
    query: { search: 'keyword' }
  })

  // 带 replace 的导航
  router.replace('/home')

  // 前进/后退
  router.go(-1) // 后退
  router.go(1)  // 前进
}

// 获取当前路由信息
console.log(route.params.id)
console.log(route.query.search)
</script>

5. 路由懒加载

// 基础懒加载
const routes = [
  {
    path: '/home',
    component: () => import('@/views/Home.vue')
  }
]

// 分组懒加载
const routes = [
  {
    path: '/admin',
    component: () => import(/* webpackChunkName: "admin" */ '@/views/Admin.vue')
  }
]

6. 路由模式对比

// Hash 模式 (#)
const router = createRouter({
  history: createWebHashHistory(),
  routes
})

// History 模式 (需要服务器配置)
const router = createRouter({
  history: createWebHistory(),
  routes
})

7. 实际应用示例

// 权限路由示例
const router = createRouter({
  history: createWebHistory(),
  routes: [
    {
      path: '/login',
      component: () => import('@/views/Login.vue')
    },
    {
      path: '/',
      component: () => import('@/layouts/MainLayout.vue'),
      children: [
        {
          path: 'dashboard',
          component: () => import('@/views/Dashboard.vue'),
          meta: {
            requiresAuth: true,
            roles: ['admin', 'user']
          }
        }
      ]
    }
  ]
})

// 权限守卫
router.beforeEach(async (to, from, next) => {
  const store = useStore()
  
  if (to.meta.requiresAuth) {
    if (!store.isLoggedIn) {
      next('/login')
    } else if (to.meta.roles && !to.meta.roles.includes(store.userRole)) {
      next('/403')
    } else {
      next()
    }
  } else {
    next()
  }
})

要点:

  1. 路由模式区别:
  • Hash 模式:使用 URL hash 变化触发路由,兼容性好

  • History 模式:需要服务器配置,但 URL 更美观

  1. 导航守卫执行顺序:
  • 导航被触发

  • 在失活的组件里调用 beforeRouteLeave

  • 调用全局 beforeEach 守卫

  • 在重用的组件里调用 beforeRouteUpdate

  • 在路由配置里调用 beforeEnter

  • 解析异步路由组件

  • 在被激活的组件里调用 beforeRouteEnter

  • 调用全局 beforeResolve 守卫

  • 导航确认

  • 调用全局 afterEach 钩子

  • DOM 更新

  • 调用 beforeRouteEnter 守卫中传给 next 的回调函数

  1. 性能优化:
  • 路由懒加载

  • 路由组件缓存 (keep-alive)

  • 预加载关键路由

  1. 安全考虑:
  • 权限控制

  • 路由参数验证

  • 防止重复点击