Vue Router
什么是 Vue Router?
Vue Router 是 Vue.js 官方的路由管理器,用于构建单页应用(SPA)。它与 Vue.js 核心深度集成,让构建单页应用变得更加简单。
1. 安装 Vue Router
使用 npm 或 yarn 安装 Vue Router。
示例:安装 Vue Router
# 使用 npm
npm install vue-router@4
# 使用 yarn
yarn add vue-router@4
2. 基本配置
创建路由配置文件,并在应用中使用。
示例:路由配置
// router/index.js
import { createRouter, createWebHistory } from 'vue-router'
// 导入组件
import HomeView from '../views/HomeView.vue'
import AboutView from '../views/AboutView.vue'
import ContactView from '../views/ContactView.vue'
// 定义路由
const routes = [
{
path: '/',
name: 'home',
component: HomeView
},
{
path: '/about',
name: 'about',
component: AboutView
},
{
path: '/contact',
name: 'contact',
component: ContactView
}
]
// 创建路由实例
const router = createRouter({
// 路由模式:createWebHistory (HTML5 History API) 或 createWebHashHistory (hash 模式)
history: createWebHistory(import.meta.env.BASE_URL),
routes
})
export default router
在应用中使用路由
// 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')
App.vue 中添加路由出口
<template>
<div id="app">
<nav>
<router-link to="/">首页</router-link> |
<router-link to="/about">关于我们</router-link> |
<router-link to="/contact">联系我们</router-link>
</nav>
<!-- 路由出口:匹配的组件将渲染在这里 -->
<router-view />
</div>
</template>
3. 路由导航
Vue Router 提供了多种导航方式:
3.1 声明式导航
使用 <router-link> 组件进行导航。
示例:声明式导航
<!-- 基本导航 -->
<router-link to="/">首页</router-link>
<!-- 命名路由 -->
<router-link :to="{ name: 'about' }">关于我们</router-link>
<!-- 带参数的路由 -->
<router-link :to="{ name: 'user', params: { id: 123 } }">用户 123</router-link>
<!-- 带查询参数 -->
<router-link :to="{ path: '/search', query: { q: 'vue' } }">搜索 Vue</router-link>
<!-- 替换当前历史记录 -->
<router-link to="/" replace>首页</router-link>
<!-- 激活状态样式 -->
<router-link to="/" active-class="active">首页</router-link>
3.2 编程式导航
使用 router.push() 或 router.replace() 进行导航。
示例:编程式导航
<template>
<div>
<button @click="goToHome">返回首页</button>
<button @click="goToAbout">前往关于页</button>
<button @click="goToUser">查看用户</button>
<button @click="goBack">返回上一页</button>
</div>
</template>
<script setup>
import { useRouter, useRoute } from 'vue-router';
const router = useRouter();
const route = useRoute();
// 前往首页
function goToHome() {
router.push('/');
}
// 前往关于页
function goToAbout() {
router.push({ name: 'about' });
}
// 查看用户
function goToUser() {
router.push({ name: 'user', params: { id: 123 } });
}
// 返回上一页
function goBack() {
router.back();
// 或 router.go(-1);
}
</script>
4. 动态路由
使用动态路由参数匹配不同的路由。
示例:动态路由
// router/index.js
const routes = [
{
path: '/user/:id',
name: 'user',
component: () => import('../views/UserView.vue')
},
{
path: '/post/:year/:month/:day',
name: 'post',
component: () => import('../views/PostView.vue')
}
]
在组件中获取路由参数
<template>
<div class="user">
<h2>用户详情</h2>
<p>用户 ID: {{ route.params.id }}</p>
<p>查询参数: {{ route.query }}</p>
<p>路由名称: {{ route.name }}</p>
<p>完整路径: {{ route.fullPath }}</p>
</div>
</template>
<script setup>
import { useRoute } from 'vue-router';
const route = useRoute();
// 监听路由参数变化
import { watch } from 'vue';
watch(() => route.params.id, (newId, oldId) => {
console.log(`用户 ID 从 ${oldId} 变为 ${newId}`);
// 可以在这里重新获取数据
});
</script>
5. 嵌套路由
使用嵌套路由实现复杂的页面结构。
示例:嵌套路由
// router/index.js
const routes = [
{
path: '/dashboard',
name: 'dashboard',
component: () => import('../views/DashboardView.vue'),
children: [
{
path: '', // 默认子路由
name: 'dashboard-home',
component: () => import('../views/DashboardHomeView.vue')
},
{
path: 'profile',
name: 'dashboard-profile',
component: () => import('../views/DashboardProfileView.vue')
},
{
path: 'settings',
name: 'dashboard-settings',
component: () => import('../views/DashboardSettingsView.vue')
}
]
}
]
父组件中添加子路由出口
<template>
<div class="dashboard">
<h2>仪表盘</h2>
<nav>
<router-link to="/dashboard">首页</router-link>
<router-link to="/dashboard/profile">个人资料</router-link>
<router-link to="/dashboard/settings">设置</router-link>
</nav>
<!-- 子路由出口 -->
<router-view />
</div>
</template>
6. 路由守卫
路由守卫用于控制路由的访问权限,包括全局守卫、路由独享守卫和组件内守卫。
示例:全局守卫
// router/index.js
// 全局前置守卫
router.beforeEach((to, from, next) => {
console.log('全局前置守卫', to, from);
// 检查用户是否登录
const isLoggedIn = localStorage.getItem('isLoggedIn');
// 如果访问的是需要登录的页面,且用户未登录,则重定向到登录页
if (to.meta.requiresAuth && !isLoggedIn) {
next({ name: 'login' });
} else {
next(); // 继续导航
}
});
// 全局解析守卫
router.beforeResolve((to, from, next) => {
console.log('全局解析守卫', to, from);
next();
});
// 全局后置钩子
router.afterEach((to, from) => {
console.log('全局后置钩子', to, from);
// 可以在这里设置页面标题
document.title = to.meta.title || 'Vue3 App';
});
示例:路由独享守卫
const routes = [
{
path: '/admin',
name: 'admin',
component: () => import('../views/AdminView.vue'),
meta: {
requiresAuth: true,
requiresAdmin: true
},
// 路由独享守卫
beforeEnter: (to, from, next) => {
console.log('路由独享守卫', to, from);
const userRole = localStorage.getItem('userRole');
if (to.meta.requiresAdmin && userRole !== 'admin') {
next({ name: 'home' });
} else {
next();
}
}
}
]
示例:组件内守卫
<script setup>
import { onBeforeRouteEnter, onBeforeRouteUpdate, onBeforeRouteLeave } from 'vue-router';
// 进入路由前
onBeforeRouteEnter((to, from, next) => {
console.log('进入路由前', to, from);
next();
});
// 路由更新前(参数变化时)
onBeforeRouteUpdate((to, from, next) => {
console.log('路由更新前', to, from);
next();
});
// 离开路由前
onBeforeRouteLeave((to, from, next) => {
console.log('离开路由前', to, from);
// 可以在这里询问用户是否确认离开
if (confirm('确定要离开吗?')) {
next();
} else {
next(false); // 取消导航
}
});
</script>
7. 路由懒加载
使用路由懒加载可以提高应用的初始加载性能,只在需要时才加载对应的组件。
示例:路由懒加载
// router/index.js
const routes = [
{
path: '/',
name: 'home',
component: () => import('../views/HomeView.vue')
},
{
path: '/about',
name: 'about',
component: () => import('../views/AboutView.vue')
},
{
path: '/contact',
name: 'contact',
component: () => import('../views/ContactView.vue')
}
]
8. 路由元信息
使用路由元信息可以为路由添加额外的信息,如页面标题、权限要求等。
示例:路由元信息
const routes = [
{
path: '/',
name: 'home',
component: HomeView,
meta: {
title: '首页',
requiresAuth: false
}
},
{
path: '/about',
name: 'about',
component: AboutView,
meta: {
title: '关于我们',
requiresAuth: false
}
},
{
path: '/dashboard',
name: 'dashboard',
component: DashboardView,
meta: {
title: '仪表盘',
requiresAuth: true
}
}
]
9. Vue Router 最佳实践
- 使用路由懒加载提高初始加载性能
- 使用命名路由而不是硬编码路径
- 合理使用路由守卫控制访问权限
- 为路由添加元信息,便于统一管理
- 使用嵌套路由组织复杂的页面结构
- 考虑使用路由过渡动画提升用户体验
- 注意路由参数的类型转换和验证
- 避免在路由守卫中执行复杂的异步操作