路由元数据
路由元数据(meta)允许你为每条路由附加自定义数据,例如页面标题、权限要求、缓存策略等。这些数据不会影响路由的匹配逻辑,但可以在导航守卫、组件或其他地方读取和使用,是实现路由级别业务逻辑的关键机制。
定义元数据
通过 meta 字段为路由定义元数据:
ts
const routes = defineRoutes(
{
path: '/admin',
component: AdminPanel,
meta: {
requiresAuth: true,
title: '管理后台'
}
},
{
path: '/home',
component: Home,
meta: {
requiresAuth: false,
title: '首页'
}
}
)访问元数据
在组件中通过 useRoute() 获取当前路由的元数据:
tsx
import { useRoute } from 'vitarx-router'
function AdminPanel() {
const route = useRoute()
return <h1>{route.meta.title}</h1> // "管理后台"
}元数据是响应式的
route.meta 具有响应性,当导航到不同路由时,meta 会自动更新:
tsx
import { watch } from 'vitarx'
import { useRoute } from 'vitarx-router'
function App() {
const route = useRoute()
// 监听 meta 变化,动态更新页面标题
watch(
() => route.meta.title,
title => {
document.title = title || '我的应用'
}
)
return <RouterView />
}元数据合并
当路由存在嵌套关系时,子路由会继承父路由的 meta,并在同名属性上进行覆盖:
ts
const routes = defineRoutes({
path: '/admin',
meta: { requiresAuth: true, layout: 'admin' },
children: [
{
path: 'dashboard',
meta: { title: '仪表盘' }
// 最终 meta: { requiresAuth: true, layout: 'admin', title: '仪表盘' }
},
{
path: 'settings',
meta: { title: '设置', layout: 'simple' }
// 最终 meta: { requiresAuth: true, layout: 'simple', title: '设置' }
}
]
})合并规则:
- 父路由的
meta作为基础 - 子路由的
meta浅合并到父路由的meta上 - 子路由的同名属性覆盖父路由
INFO
合并是浅层的(一层展开),不会递归合并嵌套对象。如果 meta 中包含对象类型的属性,子路由的定义会完全替换父路由的同名属性。
TypeScript 扩展
通过 TypeScript 的模块扩展可以为 meta 添加自定义字段的类型声明,获得完整的代码提示和类型检查。详见 TypeScript 支持。
实际应用
元数据最常见的应用场景是与导航守卫配合,实现权限控制:
ts
import { createRouter, defineRoutes } from 'vitarx-router'
const routes = defineRoutes(
{ path: '/', component: Home, meta: { requiresAuth: false, title: '首页' } },
{ path: '/login', component: Login, meta: { requiresAuth: false, title: '登录' } },
{ path: '/admin', component: Admin, meta: { requiresAuth: true, title: '管理后台' } },
{ path: '/profile', component: Profile, meta: { requiresAuth: true, title: '个人中心' } }
)
const router = createRouter({
routes,
beforeEach(to, from) {
// 检查目标路由是否需要认证
if (to.meta.requiresAuth && !isLoggedIn()) {
// 未登录,重定向到登录页
return {
index: '/login',
query: { redirect: to.path }
}
}
},
afterEach(to) {
// 更新页面标题
if (to.meta.title) {
document.title = to.meta.title
}
}
})
function isLoggedIn(): boolean {
// 检查用户是否已登录
return !!localStorage.getItem('token')
}引用:关于导航守卫的详细用法,请参阅全局守卫。
完整示例
tsx
import { createRouter, defineRoutes, RouterView, RouterLink, useRoute, watch } from 'vitarx-router'
import { createApp } from 'vitarx'
function Home() {
return <h2>首页</h2>
}
function Login() {
return <h2>登录页</h2>
}
function Admin() {
return <h2>管理后台(需要认证)</h2>
}
function Profile() {
const route = useRoute()
return <h2>个人中心 — {route.meta.title}</h2>
}
const routes = defineRoutes(
{ path: '/', component: Home, meta: { requiresAuth: false, title: '首页' } },
{ path: '/login', component: Login, meta: { requiresAuth: false, title: '登录' } },
{ path: '/admin', component: Admin, meta: { requiresAuth: true, title: '管理后台' } },
{ path: '/profile', component: Profile, meta: { requiresAuth: true, title: '个人中心' } }
)
const router = createRouter({
routes,
beforeEach(to) {
if (to.meta.requiresAuth && !localStorage.getItem('token')) {
return { index: '/login', query: { redirect: to.path } }
}
},
afterEach(to) {
document.title = to.meta.title || '我的应用'
}
})
function App() {
return (
<div>
<nav>
<RouterLink to="/">首页</RouterLink>
<RouterLink to="/admin">管理后台</RouterLink>
<RouterLink to="/profile">个人中心</RouterLink>
</nav>
<RouterView />
</div>
)
}
createApp(App).use(router).mount('#app')