Skip to content

路由元信息 | 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: '文章详情'     // 面包屑文本
        }
      }
    ]
  }
]

访问元信息

在导航守卫中访问

路由匹配到的所有路由记录的元信息会合并到 route.meta 中:

javascript
router.beforeEach((to, from) => {
  // 检查是否需要认证
  if (to.meta.requiresAuth && !auth.isLoggedIn()) {
    return {
      path: '/login',
      query: { redirect: to.fullPath },
    }
  }
})

在组件中访问

vue
<script setup>
import { useRoute } from 'vue-router'

const route = useRoute()

// 访问元信息
console.log('页面标题:', route.meta.title)
console.log('需要认证:', route.meta.requiresAuth)
</script>

元信息合并规则

嵌套路由的元信息合并

对于嵌套路由,Vue Router 会自动合并所有匹配路由的元信息:

javascript
const routes = [
  {
    path: '/admin',
    component: AdminLayout,
    meta: { requiresAdmin: true },           // 父级元信息
    children: [
      {
        path: 'users',
        component: UserManagement,
        meta: { section: '用户管理' }        // 子级元信息
      }
    ]
  }
]

访问 /admin/users 时,route.meta 将包含:

javascript
{
  requiresAdmin: true,
  section: '用户管理'
}

冲突解决规则

如果父子路由有相同的元信息字段,子路由的值会覆盖父路由:

javascript
// 父路由
meta: { permission: 'read' }

// 子路由  
meta: { permission: 'write' }

// 合并结果
// { permission: 'write' }

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'
  }
}

使用类型安全的元信息

typescript
const routes: RouteRecordRaw[] = [
  {
    path: '/admin',
    component: AdminLayout,
    meta: {
      breadcrumb: '管理后台',    // 必需字段
      permission: 'admin',      // 必需字段,必须是特定值
      title: '管理页面'          // 可选字段
    }
  }
]

实际应用场景

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'
  }
})

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>

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
  }))
})

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} - 我的网站`
  }
})

高级技巧

动态元信息

javascript
// 根据路由参数动态设置元信息
const routes = [
  {
    path: '/user/:userId',
    component: UserProfile,
    meta: to => ({
      title: `用户 ${to.params.userId} 的资料`,
      requiresAuth: true
    })
  }
]

元信息验证

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)
  }
})

元信息工具函数

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. 保持元信息简洁

javascript
// Good: 简洁明确的元信息
meta: { 
  requiresAuth: true,
  permission: 'admin'
}

// Avoid: 过于复杂的元信息
meta: {
  auth: { required: true, level: 'admin', timeout: 3600 },
  ui: { theme: 'dark', animation: 'bounce' }
}

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'
}

3. 文档化元信息字段

javascript
/**
 * 路由元信息字段说明
 * 
 * @property {boolean} requiresAuth - 是否需要认证
 * @property {string} permission - 所需权限级别
 * @property {string} title - 页面标题
 * @property {string} breadcrumb - 面包屑文本
 * @property {string} transition - 页面过渡动画
 */

🎯 总结:路由元信息是 Vue Router 中非常强大的功能,合理使用可以大大提升应用的可维护性和灵活性。通过元信息,你可以实现复杂的业务逻辑,同时保持代码的清晰和可读性。

🚀 Vue Router - 让前端路由变得简单而强大 | 构建现代化单页应用的最佳选择