动态路由
在实际应用中,很多路由的路径结构是相似的,只有某些部分不同。例如用户详情页 /user/123 和 /user/456,它们共享相同的页面结构,只是用户 ID 不同。动态路由允许你在路径中定义参数,匹配一类路径而非固定路径。
动态参数
使用 {param} 语法定义必填的动态参数:
ts
const routes = defineRoutes({ path: '/user/{id}', component: UserProfile })上述配置会匹配 /user/123、/user/abc 等路径,其中 {id} 部分会被提取为参数。
在组件中通过 useRoute() 获取参数:
tsx
import { useRoute } from 'vitarx-router'
function UserProfile() {
const route = useRoute()
return <div>用户 ID:{route.params.id}</div>
}访问 /user/123 时,route.params.id 的值为 "123"。
INFO
动态参数的值始终是字符串类型。如果需要数字类型,请自行转换:Number(route.params.id)。
可选参数
使用 {param?} 语法定义可选参数,带有 ? 后缀的参数可以省略:
ts
const routes = defineRoutes({ path: '/user/{id?}', component: UserProfile })上述配置会同时匹配:
/user——params.id不存在/user/123——params.id为"123"
WARNING
必填参数不能跟在可选参数后面。以下写法是无效的:
ts
// ❌ 错误:必填参数 {name} 跟在可选参数 {id?} 后面
{ path: '/user/{id?}/{name}', component: UserProfile }这是因为如果 id 被省略,name 的位置会变得不确定,导致匹配歧义。
参数约束
默认情况下,动态参数匹配 [^/]+(即除 / 外的任意字符)。你可以通过 pattern 字段为参数指定正则约束:
ts
const routes = defineRoutes({
path: '/user/{id}',
component: UserProfile,
// 约束 id 只能是数字
pattern: { id: /^d+$/ }
})配置后:
/user/123✅ 匹配成功,params.id为"123"/user/abc❌ 匹配失败,因为abc不满足^\d+$
INFO
子路由会继承父路由的 pattern 配置。如果子路由定义了同名参数的 pattern,则子路由的约束会覆盖父路由的约束。
多个参数
一条路由可以包含多个动态参数段:
ts
const routes = defineRoutes({ path: '/post/{category}/{id}', component: PostDetail })访问 /post/tech/42 时:
ts
route.params.category // "tech"
route.params.id // "42"多个参数也可以与可选参数组合使用:
ts
const routes = defineRoutes({ path: '/archive/{year}/{month?}', component: Archive })/archive/2024——params.year为"2024",params.month不存在/archive/2024/06——params.year为"2024",params.month为"06"
完整示例
tsx
import { createRouter, defineRoutes, RouterView, useRoute } from 'vitarx-router'
import { createApp } from 'vitarx'
function UserProfile() {
const route = useRoute()
return (
<div>
<h2>用户详情</h2>
<p>用户 ID:{route.params.id}</p>
</div>
)
}
function PostDetail() {
const route = useRoute()
return (
<div>
<h2>文章详情</h2>
<p>分类:{route.params.category}</p>
<p>文章 ID:{route.params.id}</p>
</div>
)
}
function Archive() {
const route = useRoute()
return (
<div>
<h2>归档</h2>
<p>年份:{route.params.year}</p>
{route.params.month && <p>月份:{route.params.month}</p>}
</div>
)
}
const routes = defineRoutes(
{ path: '/user/{id}', component: UserProfile, pattern: { id: /^d+$/ } },
{ path: '/post/{category}/{id}', component: PostDetail },
{ path: '/archive/{year}/{month?}', component: Archive }
)
const router = createRouter({ routes })
function App() {
return <RouterView />
}
createApp(App).use(router).mount('#app')