Skip to content

Vue Router 4

Vue Router 是 Vue.js 官方的路由管理器,用于构建单页面应用(SPA)。Vue Router 4 是 Vue 3 的配套路由版本,提供更灵活的 API 和更好的 TypeScript 支持。

安装与基本配置

安装

bash
npm install vue-router@4
# 或
yarn add vue-router@4

基础路由配置

javascript
// router/index.js
import { createRouter, createWebHistory } from 'vue-router'

const routes = [
  {
    path: '/',
    name: 'Home',
    component: () => import('@/views/Home.vue')
  },
  {
    path: '/about',
    name: 'About',
    component: () => import('@/views/About.vue')
  }
]

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

export default router

挂载到Vue应用

javascript
// main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'

const app = createApp(App)
app.use(router)
app.mount('#app')

核心功能

路由视图 <router-view>

vue
<!-- App.vue -->
<template>
  <router-view></router-view> <!-- 路由匹配的组件将渲染在这里 -->
</template>
vue
<template>
  <router-link to="/">首页</router-link>
  <router-link :to="{ name: 'About' }">关于</router-link>
</template>

编程式导航

javascript
import { useRouter } from 'vue-router'

// 在setup中使用
const router = useRouter()

// 跳转到指定路径
router.push('/about')

// 带参数跳转
router.push({ name: 'User', params: { id: 123 } })

// 替换当前路由(不记录历史)
router.replace('/login')

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

动态路由

基本概念

动态路由允许在路径中使用变量部分,常用于显示基于ID的内容(如用户详情、产品页面等)。

配置动态路由

javascript
// router/index.js
const routes = [
  {
    path: '/user/:id',  // :id 是动态参数
    name: 'User',
    component: () => import('@/views/User.vue')
  },
  {
    path: '/product/:category/:id',  // 多段动态参数
    component: () => import('@/views/Product.vue')
  }
]

获取动态参数

在目标组件中通过 useRoute() 获取参数:

vue
<!-- User.vue -->
<script setup>
import { useRoute } from 'vue-router'

const route = useRoute()
console.log(route.params.id) // 输出URL中的id值
</script>

高级匹配模式

模式说明示例
:id基础动态段/user/123
:id(\\d+)只匹配数字/user/123 (不匹配/user/abc)
:chapters*匹配零个或多个/a/b/c 匹配 params: { chapters: ['a', 'b', 'c'] }
:chapters+匹配一个或多个同上,但至少一个
/:pathMatch(.*)*404捕获路由匹配所有未定义路径

响应参数变化

当从 /user/1 导航到 /user/2 时,同一组件实例会被复用,需要监听参数变化:

vue
<script setup>
import { watch } from 'vue'
import { useRoute } from 'vue-router'

const route = useRoute()

watch(
  () => route.params.id,
  (newId) => {
    fetchUser(newId) // 参数变化时重新获取数据
  }
)
</script>

最佳实践

  1. 参数验证:使用正则约束参数格式

    javascript
    path: '/user/:id(\\d+)' // 只匹配数字ID
  2. Props 解耦:通过 props: true 将参数作为组件 props 传递

    javascript
    {
      path: '/user/:id',
      component: User,
      props: true // route.params 将作为 props 传入
    }

嵌套路由

基本概念

嵌套路由允许在组件内部再嵌套子路由,形成多级路由结构(如后台管理系统的布局)。

配置嵌套路由

javascript
const routes = [
  {
    path: '/dashboard',
    component: () => import('@/layouts/Dashboard.vue'),
    children: [
      {
        path: '', // 默认子路由
        component: () => import('@/views/DashboardHome.vue')
      },
      {
        path: 'profile', // 匹配 /dashboard/profile
        component: () => import('@/views/DashboardProfile.vue')
      },
      {
        path: 'settings',
        component: () => import('@/views/DashboardSettings.vue')
      }
    ]
  }
]

嵌套视图

父组件需包含 <router-view> 作为子路由出口:

vue
<!-- Dashboard.vue -->
<template>
  <div>
    <h1>Dashboard 布局</h1>
    <nav>
      <router-link to="/dashboard">首页</router-link>
      <router-link to="/dashboard/profile">个人资料</router-link>
    </nav>
    <router-view></router-view> <!-- 子路由内容渲染在这里 -->
  </div>
</template>

嵌套路由的路径行为

配置方式实际路径说明
path: 'profile'/dashboard/profile相对路径(推荐)
path: '/profile'/profile绝对路径(会跳出嵌套)

嵌套路由的命名视图

支持多个命名视图的嵌套:

javascript
{
  path: '/admin',
  components: {
    default: AdminLayout,
    sidebar: AdminSidebar
  },
  children: [
    {
      path: 'users',
      components: {
        default: UserList,
        sidebar: UserStats
      }
    }
  ]
}

最佳实践

  1. 布局提取:将公共布局抽离为父路由组件

  2. 默认子路由:始终为嵌套路由提供默认视图

  3. 路径命名:使用命名路由方便维护

    javascript
    {
      path: 'profile',
      name: 'DashboardProfile' // 全路径命名
    }

动态嵌套路由

动态子路由

javascript
{
  path: '/category/:category',
  component: Category,
  children: [
    {
      path: ':subcategory',
      component: Subcategory
    }
  ]
}
  • /category/books → 显示Category组件(无子内容)
  • /category/books/fiction → 显示Category + Subcategory组件

捕获所有子路由

javascript
{
  path: '/docs',
  component: Docs,
  children: [
    {
      path: ':pathMatch(.*)*', // 匹配所有/docs/下的路径
      component: DocPage
    }
  ]
}

导航守卫(路由拦截)

导航守卫是 Vue Router 的核心功能之一,允许您在路由导航过程中插入控制逻辑,实现权限验证、数据预加载、页面追踪等功能。

导航守卫类型

Vue Router 提供三类导航守卫:

类型调用时机使用场景
全局守卫所有路由切换权限控制、日志记录
路由独享守卫特定路由配置路由级权限校验
组件内守卫组件生命周期组件级逻辑控制

全局守卫

router.beforeEach (全局前置守卫)

javascript
const router = createRouter({ /*...*/ })

router.beforeEach((to, from, next) => {
  // to: 即将进入的路由
  // from: 当前导航正要离开的路由
  // next: 必须调用的函数
  
  if (to.meta.requiresAuth && !isAuthenticated()) {
    next('/login') // 重定向到登录页
  } else {
    next() // 放行
  }
})

next() 的三种用法

  • next(): 正常放行
  • next(false): 中断当前导航
  • next('/path'): 重定向到新路径

router.beforeResolve (全局解析守卫)

  • 在导航被确认,所有组件内守卫和异步路由组件被解析调用
  • 适合获取数据或执行动画前的最后检查
javascript
router.beforeResolve(async to => {
  if (to.meta.requiresData) {
    await fetchData(to.params.id)
  }
})

router.afterEach (全局后置钩子)

  • 导航已确认后调用,无法改变导航
  • 适合日志记录、页面分析
javascript
router.afterEach((to, from) => {
  sendToAnalytics(to.fullPath)
})

路由独享守卫

在路由配置中直接定义:

javascript
const routes = [
  {
    path: '/admin',
    component: Admin,
    beforeEnter: (to, from, next) => {
      if (!isAdmin()) {
        next('/forbidden')
      } else {
        next()
      }
    }
  }
]

特点

  • 只在进入该路由时触发
  • 比全局守卫优先级更高

组件内守卫

beforeRouteEnter

  • 在渲染该组件的对应路由被验证前调用
  • 不能访问组件实例 (this),因为组件还未创建
javascript
export default {
  beforeRouteEnter(to, from, next) {
    next(vm => {
      // 通过回调访问组件实例
      console.log(vm.$data)
    })
  }
}

beforeRouteUpdate

  • 在当前路由改变但组件被复用时调用
  • 可以访问组件实例 (this)
javascript
export default {
  beforeRouteUpdate(to, from) {
    this.fetchData(to.params.id) // 响应路由参数变化
  }
}

beforeRouteLeave

  • 在导航离开该组件的对应路由时调用
  • 常用于防止用户误操作丢失数据
javascript
export default {
  beforeRouteLeave(to, from, next) {
    if (this.hasUnsavedChanges) {
      if (confirm('有未保存的更改,确定离开吗?')) {
        next()
      } else {
        next(false)
      }
    } else {
      next()
    }
  }
}

完整导航解析流程

  1. 导航被触发
  2. 调用失活组件的 beforeRouteLeave
  3. 调用全局 beforeEach
  4. 在重用的组件里调用 beforeRouteUpdate
  5. 调用路由配置中的 beforeEnter
  6. 解析异步路由组件
  7. 调用激活组件的 beforeRouteEnter
  8. 调用全局 beforeResolve
  9. 导航被确认
  10. 调用全局 afterEach
  11. 触发 DOM 更新
  12. 调用 beforeRouteEnter 中传给 next 的回调

实战案例

登录验证

javascript
// 全局前置守卫
router.beforeEach((to, from, next) => {
  const isAuthRequired = to.matched.some(record => record.meta.requiresAuth)
  const isAuthenticated = checkAuth() // 你的验证逻辑
  
  if (isAuthRequired && !isAuthenticated) {
    next({
      path: '/login',
      query: { redirect: to.fullPath } // 登录后重定向回原页面
    })
  } else {
    next()
  }
})

页面权限控制

javascript
// 路由配置
{
  path: '/admin',
  meta: { 
    requiresRole: 'admin'
  }
}

// 全局守卫
router.beforeEach((to, from, next) => {
  const requiredRole = to.meta.requiresRole
  if (requiredRole && !hasRole(requiredRole)) {
    next('/403') // 无权限页面
  } else {
    next()
  }
})

动态标题设置

javascript
router.afterEach((to) => {
  document.title = to.meta.title || '默认标题'
})

常见问题

如何避免无限重定向?

javascript
router.beforeEach((to, from, next) => {
  if (to.path === '/login' && isAuthenticated()) {
    next('/') // 已登录时访问/login则跳转首页
  } else {
    next()
  }
})

如何获取组件实例?

javascript
beforeRouteEnter(to, from, next) {
  next(vm => {
    // vm 是组件实例
    vm.loadData()
  })
}

如何取消导航?

javascript
next(false) // 中断当前导航

最佳实践

  1. 权限验证:推荐在全局 beforeEach 中统一处理
  2. 数据预加载:使用 beforeRouteEnterbeforeResolve
  3. 敏感操作确认:在 beforeRouteLeave 中提示用户
  4. 性能优化:避免在守卫中执行耗时操作
  5. 代码组织:将复杂守卫逻辑提取到单独文件

路由元信息

定义路由元信息

javascript
{
  path: '/admin',
  component: Admin,
  meta: {
    requiresAuth: true,
    title: '管理后台'
  }
}

使用元信息

javascript
router.beforeEach((to, from, next) => {
  if (to.meta.requiresAuth) {
    // 权限校验逻辑
  }
})

路由模式

模式说明配置方式
History模式干净的URL(需要服务器支持)createWebHistory()
Hash模式带#的URL(兼容性好)createWebHashHistory()
Memory模式无URL变化(SSR/测试用)createMemoryHistory()
javascript
import { createWebHashHistory } from 'vue-router'

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

懒加载路由

javascript
// 使用动态import实现懒加载
{
  path: '/about',
  component: () => import('@/views/About.vue')
}

常见问题解决方案

路由重复导航错误

javascript
// 捕获重复导航错误
router.push('/').catch(err => {
  if (err.name !== 'NavigationDuplicated') {
    throw err
  }
})

滚动行为控制

javascript
const router = createRouter({
  scrollBehavior(to, from, savedPosition) {
    if (savedPosition) {
      return savedPosition // 返回保存的位置
    }
    return { top: 0 } // 滚动到顶部
  }
})

404页面处理

javascript
{
  path: '/:pathMatch(.*)*',
  component: () => import('@/views/NotFound.vue')
}

完整示例

路由配置

javascript
// router/index.js
import { createRouter, createWebHistory } from 'vue-router'

const routes = [
  {
    path: '/',
    name: 'Home',
    component: () => import('@/views/Home.vue'),
    meta: { title: '首页' }
  },
  {
    path: '/user/:id',
    name: 'User',
    component: () => import('@/views/User.vue'),
    props: true,
    meta: { requiresAuth: true }
  },
  {
    path: '/:pathMatch(.*)*',
    component: () => import('@/views/NotFound.vue')
  }
]

const router = createRouter({
  history: createWebHistory(),
  routes
})

router.beforeEach((to, from, next) => {
  document.title = to.meta.title || '默认标题'
  next()
})

export default router

组件使用

vue
<!-- App.vue -->
<template>
  <nav>
    <router-link to="/">首页</router-link>
    <router-link :to="{ name: 'User', params: { id: 123 } }">用户</router-link>
  </nav>
  <router-view></router-view>
</template>

总结

Vue Router 4 的核心功能包括:

  1. 声明式导航:<router-link>
  2. 编程式导航:router.push()/replace()
  3. 动态路由:参数传递与获取
  4. 嵌套路由:多级路由视图
  5. 导航守卫:路由拦截与控制
  6. 路由懒加载:优化性能
编程洪同学服务平台是一个广泛收集编程相关内容和资源,旨在满足编程爱好者和专业开发人员的需求的网站。无论您是初学者还是经验丰富的开发者,都可以在这里找到有用的信息和资料,我们将助您提升编程技能和知识。
专业开发
高端定制
售后无忧
站内资源均为本站制作或收集于互联网等平台,如有侵权,请第一时间联系本站,敬请谅解!本站资源仅限于学习与参考,严禁用于各种非法活动,否则后果自行负责,本站概不承担!