Vue Router 是 Vue.js 官方的路由管理器,用于构建单页面应用(SPA)。它能够让你在不刷新页面的情况下切换视图,提供流畅的用户体验。本教程将带你从基础到进阶全面掌握 Vue Router。
目录
安装与配置
1. 安装 Vue Router
bash
npm install vue-router@4
2. 基本配置
javascript
// router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
import About from '../views/About.vue'
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: About
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default router
3. 在 main.js 中引入
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')
基础概念
RouterView 和 RouterLink
vue
<!-- App.vue -->
<template>
<div id="app">
<nav>
<router-link to="/">首页</router-link>
<router-link to="/about">关于</router-link>
</nav>
<router-view />
</div>
</template>
<router-view>:路由出口,匹配到的组件将渲染在这里<router-link>:导航链接,默认渲染为<a>标签
路由配置
基本路由配置
javascript
const routes = [
{
path: '/', // 路径
name: 'home', // 路由名称(可选)
component: Home, // 对应组件
alias: '/home', // 别名
redirect: '/welcome' // 重定向
}
]
命名路由
javascript
{
path: '/user/:id',
name: 'user',
component: User
}
vue
<router-link :to="{ name: 'user', params: { id: 123 }}">
用户页面
</router-link>
导航方式
声明式导航
vue
<template>
<div>
<!-- 字符串路径 -->
<router-link to="/home">首页</router-link>
<!-- 使用 v-slot 自定义 -->
<router-link to="/about" v-slot="{ href, route, navigate, isActive }">
<a :href="href" @click="navigate" :class="{ active: isActive }">
{{ route.name }}
</a>
</router-link>
<!-- 对象形式 -->
<router-link :to="{ path: '/profile' }">个人资料</router-link>
<!-- 命名路由 -->
<router-link :to="{ name: 'user', params: { id: 1 } }">
用户详情
</router-link>
</div>
</template>
编程式导航
vue
<template>
<button @click="goToHome">去首页</button>
<button @click="goBack">返回</button>
</template>
<script setup>
import { useRouter } from 'vue-router'
const router = useRouter()
const goToHome = () => {
router.push('/home')
// 或者
// router.push({ name: 'home' })
}
const goBack = () => {
router.go(-1) // 后退一步
// router.back() // 等同于 router.go(-1)
}
const replaceNavigation = () => {
router.replace('/login') // 替换当前记录
}
</script>
动态路由
带参数的路由
javascript
// router/index.js
{
path: '/user/:id',
name: 'user',
component: User
}
{
path: '/product/:category/:id',
name: 'product',
component: Product
}
在组件中访问路由参数
vue
<template>
<div>
<h2>用户ID: {{ userId }}</h2>
<h2>当前路径: {{ route.path }}</h2>
</div>
</template>
<script setup>
import { useRoute } from 'vue-router'
import { computed } from 'vue'
const route = useRoute()
// 访问参数
const userId = computed(() => route.params.id)
// 访问查询参数
const searchQuery = computed(() => route.query.q)
</script>
可选参数和通配符
javascript
{
path: '/user/:id?', // 可选参数
component: User
}
{
path: '/:pathMatch(.*)*', // 通配符路由(404页面)
name: 'NotFound',
component: NotFound
}
嵌套路由
配置嵌套路由
javascript
const routes = [
{
path: '/user/:id',
component: User,
children: [
{
// 当 /user/:id/profile 匹配成功
path: 'profile',
component: UserProfile
},
{
// 当 /user/:id/posts 匹配成功
path: 'posts',
component: UserPosts
},
{
// 默认子路由
path: '',
component: UserDashboard
}
]
}
]
嵌套路由组件
vue
<!-- User.vue -->
<template>
<div class="user">
<h2>用户 {{ $route.params.id }}</h2>
<div class="user-nav">
<router-link to="profile">资料</router-link>
<router-link to="posts">文章</router-link>
</div>
<router-view /> <!-- 子路由将在这里渲染 -->
</div>
</template>
编程式导航
各种导航方法
vue
<script setup>
import { useRouter } from 'vue-router'
const router = useRouter()
// 基本导航
const navigate = () => {
// 字符串路径
router.push('/users/1')
// 对象
router.push({ path: '/users/1' })
// 命名路由
router.push({ name: 'user', params: { id: 1 } })
// 带查询参数
router.push({ path: '/search', query: { q: 'vue' } })
}
// 替换当前位置
const replace = () => {
router.replace('/login')
// 或者
router.push({ path: '/login', replace: true })
}
// 前进后退
const navigation = () => {
router.go(1) // 前进一步
router.go(-1) // 后退一步
router.back() // 后退
router.forward() // 前进
}
</script>
导航结果处理
javascript
router.push('/dashboard').then(() => {
// 导航成功
}).catch((error) => {
if (error.name === 'NavigationDuplicated') {
// 重复导航处理
console.log('重复导航到相同位置')
}
})
路由守卫
全局守卫
javascript
// router/index.js
// 全局前置守卫
router.beforeEach((to, from) => {
// 返回 false 取消导航
if (to.meta.requiresAuth && !isAuthenticated()) {
return '/login'
}
})
// 全局解析守卫
router.beforeResolve((to, from) => {
// 在导航被确认前,组件被解析后调用
})
// 全局后置钩子
router.afterEach((to, from) => {
// 导航完成后调用,无法改变导航
document.title = to.meta.title || '默认标题'
})
路由独享守卫
javascript
{
path: '/admin',
component: Admin,
beforeEnter: (to, from) => {
// 仅在此路由进入时调用
if (!isAdmin()) {
return '/login'
}
}
}
组件内守卫
vue
<script setup>
import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'
// 在组件卸载前调用
onBeforeRouteLeave((to, from) => {
const answer = window.confirm('确定要离开吗?未保存的更改将会丢失!')
if (!answer) return false
})
// 在当前路由改变但组件复用时调用
onBeforeRouteUpdate(async (to, from) => {
// 获取新的数据
userData.value = await fetchUser(to.params.id)
})
</script>
路由元信息
定义和使用元信息
javascript
const routes = [
{
path: '/admin',
component: Admin,
meta: {
requiresAuth: true,
requiresAdmin: true,
title: '管理后台'
}
},
{
path: '/profile',
component: Profile,
meta: {
requiresAuth: true,
title: '个人资料'
}
}
]
在守卫中使用元信息
javascript
router.beforeEach((to, from) => {
// 检查元信息
if (to.meta.requiresAuth && !isLoggedIn()) {
return {
path: '/login',
query: { redirect: to.fullPath }
}
}
if (to.meta.requiresAdmin && !isAdmin()) {
return '/unauthorized'
}
})
高级特性
路由懒加载
javascript
const routes = [
{
path: '/dashboard',
name: 'Dashboard',
component: () => import('../views/Dashboard.vue')
},
{
path: '/settings',
name: 'Settings',
component: () => import(/* webpackChunkName: "settings" */ '../views/Settings.vue')
}
]
滚动行为
javascript
const router = createRouter({
history: createWebHistory(),
routes,
scrollBehavior(to, from, savedPosition) {
// 返回位置
if (savedPosition) {
return savedPosition
} else if (to.hash) {
return {
el: to.hash,
behavior: 'smooth'
}
} else {
return { top: 0 }
}
}
})
路由过渡动画
vue
<template>
<router-view v-slot="{ Component }">
<transition name="fade" mode="out-in">
<component :is="Component" />
</transition>
</router-view>
</template>
<style>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
</style>
完整示例
路由配置示例
javascript
// router/index.js
import { createRouter, createWebHistory } from 'vue-router'
const routes = [
{
path: '/',
name: 'Home',
component: () => import('../views/Home.vue'),
meta: { title: '首页' }
},
{
path: '/login',
name: 'Login',
component: () => import('../views/Login.vue'),
meta: { title: '登录', guest: true }
},
{
path: '/dashboard',
name: 'Dashboard',
component: () => import('../views/Dashboard.vue'),
meta: { requiresAuth: true, title: '仪表板' }
},
{
path: '/user/:id',
name: 'User',
component: () => import('../views/User.vue'),
props: true,
meta: { requiresAuth: true },
children: [
{
path: 'profile',
name: 'UserProfile',
component: () => import('../views/UserProfile.vue')
},
{
path: 'settings',
name: 'UserSettings',
component: () => import('../views/UserSettings.vue')
}
]
},
{
path: '/:pathMatch(.*)*',
name: 'NotFound',
component: () => import('../views/NotFound.vue'),
meta: { title: '页面未找到' }
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
// 全局前置守卫
router.beforeEach((to, from) => {
const isAuthenticated = checkAuth() // 你的认证逻辑
if (to.meta.requiresAuth && !isAuthenticated) {
return {
path: '/login',
query: { redirect: to.fullPath }
}
}
if (to.meta.guest && isAuthenticated) {
return '/dashboard'
}
})
// 全局后置守卫
router.afterEach((to) => {
document.title = to.meta.title || '我的应用'
})
export default router
总结
Vue Router 是 Vue.js 生态中非常重要的组成部分,它提供了:
- 声明式路由配置:直观的路由映射关系
- 编程式导航:灵活的导航控制
- 路由守卫:完善的权限控制和导航拦截
- 嵌套路由:复杂页面结构的组织
- 懒加载:优化应用性能
- 过渡效果:提升用户体验