如何在项目中实现页面切换,而不用每次都重新加载整个页面?答案就是 Vue Router。这篇就来聊聊 Vue Router 4.x 在 Vue 3 中的集成与使用,分析它的基础配置、路由守卫和懒加载等核心概念到底是怎么回事。
- Vue Router 与 SPA:它是什么,解决了什么问题?
- 基本用法:如何安装、配置、挂载,并在组件中使用。
- 高级用法:路由守卫、懒加载、嵌套路由与参数传递。
- 常见问题与注意事项:入坑必知的几个要点。
一、什么是 Vue Router?有什么作用?
Vue Router 是 Vue.js 的官方路由管理器,用于构建单页面应用程序(SPA) 。它通过监听 URL 的变化,动态地切换页面中显示的内容组件,而无需重新加载整个网页,从而实现流畅的用户体验。
1.1 核心使用场景
- 构建单页面应用程序(SPA)
- 需要前端路由管理的项目,例如后台管理系统、多页面应用
- 需要实现页面导航 、路由守卫 (权限控制)和懒加载(按需加载)等功能
- 需要基于路由的参数传递 和状态管理
1.2 常见坑:版本匹配问题
Vue Router 4.x 专为 Vue 3 设计,不兼容 Vue 2。如果项目是 Vue 2,请使用 Vue Router 3.x。这是一个新手最容易踩的坑。
二、基本用法:最小配置与核心概念
先给结论:引入 Vue Router 主要分三步------安装 、配置路由 、挂载到应用。下面具体拆解一下。
第一步:安装
根据你的包管理器选择一种方式安装:
bash
npm install vue-router@4
# 或者
yarn add vue-router@4
# 或者
pnpm add vue-router@4
第二步:配置路由实例
在 src 目录下创建 router/index.ts 文件。这是整个应用路由的配置中心。
tsx
// src/router/index.ts
import { createRouter, createWebHistory, type RouteRecordRaw } from 'vue-router'
// 1. 定义路由配置
const routes: Array<RouteRecordRaw> = [
{
path: '/',
name: 'Home',
component: () => import('@/views/HomeView.vue') // 使用懒加载
},
{
path: '/about',
name: 'About',
component: () => import('@/views/AboutView.vue')
},
{
path: '/user/:id',
name: 'User',
component: () => import('@/views/UserView.vue'),
props: true // 将路由参数作为 props 传递给组件
}
]
// 2. 创建路由实例
const router = createRouter({
history: createWebHistory(), // 使用 HTML5 History 模式
routes
})
export default router
代码解析:
-
createRouter 和createWebHistory:这是创建 Vue Router 实例的两个核心 API。createRouter接收一个配置对象,createWebHistory表示启用history模式。 -
component: () => import(...) :这是路由懒加载 的标准写法。它告诉 Vue Router 在用户首次访问/about路由时,才去加载AboutView.vue组件,而不是在应用启动时就加载所有页面。这能显著提升首屏加载速度。 -
props: true :将:id等路由参数直接以 props 的形式注入到组件中,让组件更纯粹,方便测试和复用。
第三步:挂载到 Vue 应用
在 main.ts 中将创建好的路由实例挂载到 Vue 应用上。
tsx
// main.ts
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(router) // 挂载路由插件
app.mount('#app')
第四步:在组件中使用
在 App.vue 或其他组件中,使用 <router-link> 进行页面跳转,使用 <router-view> 作为页面内容的占位符。
vue
<template>
<div>
<nav>
<router-link to="/">首页</router-link>
<router-link to="/about">关于</router-link>
<router-link :to="{ name: 'User', params: { id: 123 }}">用户页面</router-link>
</nav>
<!-- 路由出口:匹配到的组件将在此渲染 -->
<router-view />
</div>
</template>
<script lang="ts" setup>
import { useRouter, useRoute } from 'vue-router'
// 获取路由实例和当前路由对象
const router = useRouter()
const route = useRoute()
// 编程式导航(通过代码跳转)
const goToAbout = () => {
router.push('/about')
// 或者使用命名路由
// router.push({ name: 'About' })
}
// 带参数的跳转
const goToUser = (id: number) => {
router.push({ name: 'User', params: { id } })
}
// 替换当前路由(不会在浏览器历史中留下记录)
const replaceRoute = () => {
router.replace('/about')
}
// 前进后退
const goBack = () => router.go(-1)
const goForward = () => router.go(1)
</script>
三、路由守卫与懒加载实践
在真实的项目中,我们通常需要更复杂的配置,例如全局的权限控制、全局的进度条加载动画和嵌套路由。
3.1 路由模式
| 模式 | 核心原理 | 优点 | 缺点 | 适合场景 |
|---|---|---|---|---|
hash 模式 (createWebHashHistory) |
URL 中以 #/about 形式呈现,# 后的变化不会触发服务器请求 |
无需服务器配置,兼容性好 | URL 不够美观,有 # 符号 |
静态站点、简单演示项目 |
history 模式 (createWebHistory) |
URL 是正常的 /about 形式,模拟传统网站 |
URL 美观,用户体验好 | 需要服务器配置,否则刷新页面会 404 | 生产环境、需要 SEO 的项目 |
划重点: 在正式项目中,推荐使用 history 模式,但一定不要忘记在 Nginx、Apache 等服务器上配置 try_files $uri $uri/ /index.html,否则用户直接访问 /about 页面时会返回 404。
3.2 高级配置:集成路由守卫与进度条
这个示例展示了更完整的项目级配置:将路由配置分离 ,并在路由守卫中集成全局进度条。
tsx
// src/router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
import routes from './routes' // 路由配置单独管理
import NProgress from 'nprogress'
const router = createRouter({
history: createWebHistory(),
routes
})
/**
* 全局前置守卫
* 作用:在每次路由跳转前执行,用于控制访问权限、设置页面标题、开启进度条等。
*/
router.beforeEach((_to, _from, next) => {
NProgress.start() // 开启页面顶部进度条
// 这里可以做权限验证,例如检查 token 是否存在
// if (to.meta.requiresAuth && !isLoggedIn) { next('/login') }
// else { next() }
next()
})
/**
* 全局后置守卫
* 作用:在路由跳转完成后执行,用于关闭进度条、埋点上报等。
*/
router.afterEach(() => {
NProgress.done() // 关闭进度条
})
export default router
路由守卫的核心逻辑是
next() 函数。切记:在每个判断分支都一定要调用next(),否则页面会卡住。这是新手最常犯的错误。
3.3 路由配置分离(示例)
将路由配置独立成文件 src/router/routes.ts,方便管理和扩展。
tsx
// src/router/routes.ts
import { type RouteRecordRaw } from 'vue-router'
const routes: RouteRecordRaw[] = [
{
path: '/index',
name: 'index',
component: () => import('../components/Homepage.vue'),
meta: { keepAlive: true }, // 自定义元数据
children: [
{
path: 'article',
name: 'article',
component: () => import('../views/page/article/index.vue')
}
]
},
{
path: '/',
redirect: { name: 'index' } // 重定向
}
]
export default routes
3.4 组件级别的路由出口与 keep-alive
当使用 <router-view> 时,可以结合 Vue 的 <keep-alive> 组件,实现页面状态的缓存(例如避免表单位置丢失)。
vue
<template>
<div id="app">
<router-view v-slot="{ Component }">
<!-- 当路由的 meta 中 keepAlive 为 true 时,缓存组件 -->
<keep-alive>
<component :is="Component" v-if="$route.meta.keepAlive" />
</keep-alive>
<!-- 否则不缓存 -->
<component :is="Component" v-if="!$route.meta.keepAlive" />
</router-view>
</div>
</template>
四、路由高级用法:嵌套路由与参数处理
4.1 嵌套路由
嵌套路由用于构建页面内部的子导航,比如一个后台管理系统的侧边栏内容。在上面的 routes.ts 示例中,children 数组就是嵌套路由的用法:访问 /index/article 时,ArticleView 组件会渲染在父组件 Homepage.vue 的 <router-view> 中。
4.2 动态路由参数与监听变化
当路由参数变化时(比如从 /user/1 跳转到 /user/2),组件实例会被复用 ,这意味着组件的 created 或 mounted 钩子不会再次执行。此时,你需要监听 route 对象的变化来获取新的参数并获取数据。
vue
<script setup>
import { useRoute } from 'vue-router'
import { watch } from 'vue'
const route = useRoute()
// 监听路由参数的变化
watch(() => route.params.id, (newId, oldId) => {
console.log('用户 ID 从', oldId, '变为', newId)
// 在这里调用获取用户详情数据的 API
})
</script>
五、常见问题与注意事项
- 动态路由参数变化组件不重新创建 :如上文所述,需要通过
watch监听route.params来响应变化。 - 路由配置应合理组织 :避免过于复杂的嵌套,建议将功能相关的路由放在同一个模块的
children中。 - 路由守卫执行顺序 :全局守卫(
global.beforeEach)→ 路由配置守卫(beforeEnter)→ 组件内守卫(beforeRouteEnter)。理解这个顺序对权限控制至关重要。 - props 传参 :推荐在配置路由时启用
props: true,这能让组件与路由解耦,更易于测试和维护。
最后
Vue Router 是 Vue 3 生态中一个稳定且强大 的核心库。写 SPA 项目,99% 的场景都离不开它。记住 版本匹配 和 路由守卫的 next 这两个关键点,基本就能应对大多数日常开发了。