Vue Router 是 Vue.js 官方路由库,与 Vue 核心深度集成。从 Vue Router 3(Vue 2)到 Vue Router 4(Vue 3),API 全面拥抱 Composition API,同时保持与 Options API 的兼容。本文覆盖从基础配置到生产级导航守卫策略的完整实践。
一、路由基础配置
1.1 创建 Router(v4 推荐写法)
// router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'Home',
component: Home,
},
{
path: '/about',
name: 'About',
component: () => import('../views/About.vue'), // 懒加载
},
{
path: '/users/:id',
name: 'UserProfile',
component: () => import('../views/UserProfile.vue'),
props: true, // 将路由参数作为 props 传递
},
],
})
export default router
1.2 在应用中使用
// main.ts
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
createApp(App).use(router).mount('#app')
<!-- App.vue -->
<template>
<nav>
<RouterLink to="/">Home</RouterLink>
<RouterLink to="/about">About</RouterLink>
</nav>
<main>
<RouterView /> <!-- 路由组件渲染位置 -->
</main>
</template>
1.3 Hash vs History 模式
| 模式 | 用法 | URL | 需服务器配置 | 适用 |
|---|---|---|---|---|
createWebHistory() | History API | /users/123 | ✅ 需回退 | 生产环境 |
createWebHashHistory() | Hash | /#/users/123 | ❌ 无需 | 静态托管、Electron |
createMemoryHistory() | 内存 | 不可见 | ❌ | SSR、测试 |
二、嵌套路由与命名路由
2.1 嵌套结构
const routes = [
{
path: '/dashboard',
component: DashboardLayout,
children: [
{ path: '', name: 'DashboardHome', component: DashboardHome }, // /dashboard
{ path: 'analytics', name: 'Analytics', component: Analytics }, // /dashboard/analytics
{ path: 'settings', name: 'Settings', component: Settings }, // /dashboard/settings
],
},
]
<!-- DashboardLayout.vue -->
<template>
<div class="dashboard">
<Sidebar />
<div class="content">
<RouterView /> <!-- 渲染子路由组件 -->
</div>
</div>
</template>
2.2 命名视图(多 <RouterView>)
const routes = [
{
path: '/',
components: {
default: Home,
sidebar: Sidebar, // <RouterView name="sidebar" />
footer: Footer, // <RouterView name="footer" />
},
},
]
三、动态路由与匹配
3.1 路径参数
const routes = [
// /users/123 → { id: '123' }
{ path: '/users/:id', component: UserProfile, props: true },
// /posts/2024/08/article-slug → { year: '2024', month: '08', slug: 'article-slug' }
{ path: '/posts/:year/:month/:slug', component: PostDetail },
// 可选参数(?)
{ path: '/users/:id?', component: UserProfile }, // /users 和 /users/123 都匹配
// 正则限制
{ path: '/users/:id(\\d+)', component: UserById }, // 只允许数字
]
3.2 在组件中读取参数
<script setup>
import { useRoute } from 'vue-router'
import { watch } from 'vue'
const route = useRoute()
// 读取参数
console.log(route.params.id)
// 读取查询参数 /search?q=vue → { q: 'vue' }
console.log(route.query.q)
// 读取 hash
console.log(route.hash)
// 监听参数变化(组件复用时不会重新挂载)
watch(() => route.params.id, (newId) => {
fetchUser(newId)
})
</script>
3.3 编程式导航
import { useRouter } from 'vue-router'
const router = useRouter()
// 字符串路径
router.push('/users/123')
// 带查询参数
router.push({ path: '/search', query: { q: 'vue' } })
// 命名路由 + 参数
router.push({ name: 'UserProfile', params: { id: '123' } })
// 替换当前历史(不增加记录)
router.replace('/home')
// 后退
router.back()
router.go(-1)
四、导航守卫
4.1 全局前置守卫(鉴权)
// router/index.ts
router.beforeEach(async (to, from) => {
const authStore = useAuthStore()
// 需要登录但未登录 → 跳转登录
if (to.meta.requiresAuth && !authStore.isLoggedIn) {
return { name: 'Login', query: { redirect: to.fullPath } }
}
// 需要管理员权限
if (to.meta.requiresAdmin && authStore.user?.role !== 'admin') {
return { name: 'Unauthorized' }
}
// 已登录访问登录页 → 跳转首页
if (to.name === 'Login' && authStore.isLoggedIn) {
return { name: 'Home' }
}
})
4.2 路由独享守卫
const routes = [
{
path: '/admin',
component: AdminPanel,
beforeEnter: (to, from) => {
const auth = useAuthStore()
if (!auth.isAdmin) return { name: 'Unauthorized' }
},
},
]
4.3 组件内守卫
<script setup>
import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'
// 离开守卫(如未保存表单时确认)
onBeforeRouteLeave((to, from) => {
const answer = window.confirm('You have unsaved changes. Leave?')
if (!answer) return false // 阻止导航
})
// 组件复用时更新(如 /users/1 → /users/2)
onBeforeRouteUpdate((to, from) => {
// 复用组件,只需更新数据
userId.value = to.params.id
fetchUserData(to.params.id)
})
</script>
4.4 守卫执行顺序
导航触发
↓
beforeLeave(组件内)
↓
beforeEach(全局)
↓
beforeEnter(路由独享)
↓
beforeRouteEnter(组件内)
↓
路由解析
↓
全局 afterEach
五、滚动行为与过渡
5.1 滚动恢复
const router = createRouter({
history: createWebHistory(),
routes,
scrollBehavior(to, from, savedPosition) {
// 返回历史位置(浏览器前进/后退)
if (savedPosition) {
return savedPosition
}
// hash 锚点跳转
if (to.hash) {
return { el: to.hash, behavior: 'smooth' }
}
// 默认滚动到顶部
return { top: 0, left: 0 }
},
})
5.2 路由过渡动画
<template>
<RouterView v-slot="{ Component }">
<Transition name="fade" mode="out-in">
<component :is="Component" />
</Transition>
</RouterView>
</template>
<style>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
</style>
六、懒加载与代码分割
const routes = [
{
path: '/dashboard',
component: () => import('../views/Dashboard.vue'),
// Webpack chunk name(Vite 需配置)
// component: () => import(/* webpackChunkName: "dashboard" */ '../views/Dashboard.vue'),
},
]
预加载:
<script setup>
// 鼠标悬停时预加载
const prefetchDashboard = () => {
import('../views/Dashboard.vue')
}
</script>
<template>
<RouterLink to="/dashboard" @mouseenter="prefetchDashboard">
Dashboard
</RouterLink>
</template>
常见问题(FAQ)
<RouterLink> 和 <a> 有什么区别?
<RouterLink> 使用客户端导航(不刷新页面),<a> 触发整页刷新。外部链接用 <a>,内部路由用 <RouterLink>。
路由参数变化组件不复用怎么办?
添加 :key 强制重新挂载:<RouterView :key="$route.fullPath" />,但会丢失组件状态。
如何处理 404?
{ path: '/:pathMatch(.*)*', name: 'NotFound', component: NotFound }
相关阅读
- Vue 详解 — Vue 核心概念与渐进式理念
- Vue Composition API 完全指南 —
<script setup>+ useRoute/useRouter - Pinia 状态管理指南 — 全局状态与路由结合
- Nuxt.js 完全指南 — 文件系统路由与约定
- React Router 完全指南 — React 生态的路由方案
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。
「frontend」更多文章
Vue 性能优化指南:虚拟列表、懒加载、渲染优化与 Core Web Vitals
Vue 3 应用性能优化完整策略:虚拟滚动(vue-virtual-scroller)、组件懒加载与异步组件、KeepAlive 缓存、Suspense 异步优化、v-memo 渲染记忆化、响应式性能(shallowRef/toRaw)、Bundle 分析与代码分割、渲染函数优化、以及 Core Web Vitals(LCP/INP/CLS)调优。
Nuxt.js 完全指南:Vue 全栈框架的 SSR、SSG、API 路由与部署实践
Nuxt.js 3 深度实践:文件系统路由、SSR/SSG/ISR 渲染模式、API 路由(Server Routes)、useFetch/useAsyncData 数据获取、中间件与插件、SEO 与 Meta 管理、Nitro 服务端引擎、自动导入、部署到 Vercel/Netlify/Node.js。
Vue 测试深度指南:Vitest + Vue Test Utils + Playwright E2E 与 CI 集成
Vue 3 应用从单元测试到 E2E 的完整测试策略:Vitest + Vue Test Utils 组件测试(mount/emits/slots/async)、Pinia Store Mocking、MSW API 拦截、Playwright 端到端测试、Cypress 组件测试、覆盖率标准与 GitHub Actions CI 集成。