路由元信息 | Vue Router
什么是路由元信息?
路由元信息(Route Meta)允许你为路由附加任意自定义数据,这些数据可以在导航守卫和组件中访问。常见的应用场景包括权限控制、页面过渡动画、面包屑导航等。
基本用法
定义元信息
在路由配置中使用 meta 字段定义元信息:
javascript
const routes = [
{
path: '/posts',
component: PostsLayout,
children: [
{
path: 'new',
component: PostsNew,
meta: {
requiresAuth: true, // 需要认证
transition: 'slide-left' // 页面过渡效果
}
},
{
path: ':id',
component: PostsDetail,
meta: {
requiresAuth: false, // 公开访问
breadcrumb: '文章详情' // 面包屑文本
}
}
]
}
]1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
访问元信息
在导航守卫中访问
路由匹配到的所有路由记录的元信息会合并到 route.meta 中:
javascript
router.beforeEach((to, from) => {
// 检查是否需要认证
if (to.meta.requiresAuth && !auth.isLoggedIn()) {
return {
path: '/login',
query: { redirect: to.fullPath },
}
}
})1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
在组件中访问
vue
<script setup>
import { useRoute } from 'vue-router'
const route = useRoute()
// 访问元信息
console.log('页面标题:', route.meta.title)
console.log('需要认证:', route.meta.requiresAuth)
</script>1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
元信息合并规则
嵌套路由的元信息合并
对于嵌套路由,Vue Router 会自动合并所有匹配路由的元信息:
javascript
const routes = [
{
path: '/admin',
component: AdminLayout,
meta: { requiresAdmin: true }, // 父级元信息
children: [
{
path: 'users',
component: UserManagement,
meta: { section: '用户管理' } // 子级元信息
}
]
}
]1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
访问 /admin/users 时,route.meta 将包含:
javascript
{
requiresAdmin: true,
section: '用户管理'
}1
2
3
4
2
3
4
冲突解决规则
如果父子路由有相同的元信息字段,子路由的值会覆盖父路由:
javascript
// 父路由
meta: { permission: 'read' }
// 子路由
meta: { permission: 'write' }
// 合并结果
// { permission: 'write' }1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
TypeScript 支持
定义元信息类型
为元信息字段添加 TypeScript 类型支持:
typescript
// types/router.d.ts
import 'vue-router'
declare module 'vue-router' {
interface RouteMeta {
// 可选字段
title?: string
requiresAuth?: boolean
transition?: string
// 必需字段
breadcrumb: string
permission: 'read' | 'write' | 'admin'
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
使用类型安全的元信息
typescript
const routes: RouteRecordRaw[] = [
{
path: '/admin',
component: AdminLayout,
meta: {
breadcrumb: '管理后台', // 必需字段
permission: 'admin', // 必需字段,必须是特定值
title: '管理页面' // 可选字段
}
}
]1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
实际应用场景
1. 权限控制系统
javascript
const routes = [
{
path: '/dashboard',
component: Dashboard,
meta: {
requiresAuth: true,
permissions: ['user.read', 'user.write']
}
},
{
path: '/admin',
component: AdminPanel,
meta: {
requiresAuth: true,
permissions: ['admin.access'],
role: 'administrator'
}
}
]
// 权限检查守卫
router.beforeEach((to, from) => {
if (to.meta.requiresAuth && !auth.isLoggedIn()) {
return '/login'
}
if (to.meta.permissions && !hasPermissions(to.meta.permissions)) {
return '/access-denied'
}
})1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2. 页面过渡效果
javascript
const routes = [
{
path: '/',
component: Home,
meta: { transition: 'fade' }
},
{
path: '/about',
component: About,
meta: { transition: 'slide-left' }
},
{
path: '/contact',
component: Contact,
meta: { transition: 'slide-right' }
}
]
// 在根组件中应用过渡效果
<router-view v-slot="{ Component, route }">
<transition :name="route.meta.transition || 'fade'">
<component :is="Component" />
</transition>
</router-view>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
3. 面包屑导航
javascript
const routes = [
{
path: '/products',
component: ProductsLayout,
meta: { breadcrumb: '商品' },
children: [
{
path: ':category',
component: ProductCategory,
meta: { breadcrumb: '分类' },
children: [
{
path: ':id',
component: ProductDetail,
meta: { breadcrumb: '详情' }
}
]
}
]
}
]
// 面包屑组件
const breadcrumbs = computed(() => {
return route.matched.map(record => ({
name: record.meta.breadcrumb,
path: record.path
}))
})1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
4. SEO 优化
javascript
const routes = [
{
path: '/blog/:slug',
component: BlogPost,
meta: {
title: '博客文章',
description: '精彩的博客文章内容',
keywords: 'vue,router,教程',
ogImage: '/og-image.jpg'
}
}
]
// 在布局组件中设置页面标题
watchEffect(() => {
if (route.meta.title) {
document.title = `${route.meta.title} - 我的网站`
}
})1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
高级技巧
动态元信息
javascript
// 根据路由参数动态设置元信息
const routes = [
{
path: '/user/:userId',
component: UserProfile,
meta: to => ({
title: `用户 ${to.params.userId} 的资料`,
requiresAuth: true
})
}
]1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
元信息验证
javascript
// 验证元信息格式
function validateRouteMeta(meta) {
const schema = {
title: 'string|optional',
requiresAuth: 'boolean|optional',
permissions: 'array|optional'
}
return validateSchema(meta, schema)
}
router.beforeEach((to, from) => {
if (!validateRouteMeta(to.meta)) {
console.warn('无效的路由元信息:', to.meta)
}
})1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
元信息工具函数
javascript
// 创建元信息工具库
const metaUtils = {
// 检查权限
hasPermission(route, permission) {
return route.meta.permissions?.includes(permission) ?? false
},
// 获取面包屑
getBreadcrumbs(route) {
return route.matched
.filter(record => record.meta.breadcrumb)
.map(record => ({
text: record.meta.breadcrumb,
path: record.path
}))
},
// 设置页面标题
setDocumentTitle(route) {
if (route.meta.title) {
document.title = route.meta.title
}
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
最佳实践
1. 保持元信息简洁
javascript
// Good: 简洁明确的元信息
meta: {
requiresAuth: true,
permission: 'admin'
}
// Avoid: 过于复杂的元信息
meta: {
auth: { required: true, level: 'admin', timeout: 3600 },
ui: { theme: 'dark', animation: 'bounce' }
}1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
2. 使用常量定义
javascript
// meta-constants.js
export const META = {
AUTH: {
REQUIRED: 'requiresAuth',
PERMISSION: 'permission'
},
UI: {
TRANSITION: 'transition',
LAYOUT: 'layout'
}
}
// 使用常量
meta: {
[META.AUTH.REQUIRED]: true,
[META.UI.TRANSITION]: 'fade'
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
3. 文档化元信息字段
javascript
/**
* 路由元信息字段说明
*
* @property {boolean} requiresAuth - 是否需要认证
* @property {string} permission - 所需权限级别
* @property {string} title - 页面标题
* @property {string} breadcrumb - 面包屑文本
* @property {string} transition - 页面过渡动画
*/1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
🎯 总结:路由元信息是 Vue Router 中非常强大的功能,合理使用可以大大提升应用的可维护性和灵活性。通过元信息,你可以实现复杂的业务逻辑,同时保持代码的清晰和可读性。