Skip to content

01|路由表与匹配 ​

第六章概览 / 01。目标:把路由表理解为“URL → matched route records”的解析规则,而不是菜单数组。

最小 Router 4 配置 ​

ts
// src/router.ts
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from './views/HomeView.vue'
import UserView from './views/UserView.vue'
import NotFoundView from './views/NotFoundView.vue'

export const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    { path: '/', name: 'home', component: HomeView },
    { path: '/users/:id', name: 'user', component: UserView },
    { path: '/:pathMatch(.*)*', name: 'not-found', component: NotFoundView },
  ],
})
ts
// src/main.ts
createApp(App).use(router).mount('#app')

history 决定 URL 如何与浏览器会话历史连接;routes 是 route records。访问 /users/42 时匹配 user,并得到字符串参数 route.params.id === '42'。catch-all 的 * 让 pathMatch 是可重复参数,使用命名路由生成 404 地址时可传字符串数组。

静态、动态与自定义正则 ​

ts
const routes = [
  { path: '/orders/new', name: 'order-new', component: NewOrderView },
  { path: '/orders/:id(\\d+)', name: 'order', component: OrderView },
  { path: '/articles/:slug?', name: 'article', component: ArticleView },
  { path: '/chapters/:parts+', name: 'chapters', component: ChaptersView },
]
写法匹配params 形状
/orders/new只匹配固定文本无
/orders/:id(\\d+)id 只允许数字string
/articles/:slug?slug 有或没有string 或空值
/chapters/:parts+至少一个路径段string[]

JavaScript 字符串里的反斜杠要转义,所以数字约束写成 \\d+。动态正则末尾的 */+ 属于参数修饰符,不是正则本身。

Vue Router 4 会对路由模式评分,静态段通常比动态段更具体,因此 /orders/new 不会因为写在动态路由后就必然被 :id 抢走。不要把数组顺序当主要优先级控制;用静态段、明确正则和 router.resolve() 测试合同。完全相同/别名等价的记录仍应避免歧义。

用 router.resolve() 做无副作用匹配实验 ​

ts
const order = router.resolve('/orders/42')
console.log(order.name, order.params.id, order.matched.length)

const unknown = router.resolve('/orders/nope')
console.log(unknown.name) // not-found

const chapters = router.resolve({
  name: 'chapters',
  params: { parts: ['vue', 'router'] },
})
console.log(chapters.href) // /chapters/vue/router(base 可能不同)

resolve() 规范化位置并返回 href/matched/name/params,但不会改变当前 URL,也不会运行导航守卫。它适合路由表单元测试;真正的导航行为还要用 router.push() 和浏览器验证。

三种 history owner ​

创建函数使用场景责任
createWebHistory(base?)普通浏览器 SPA干净 URL;服务器必须配置 fallback
createWebHashHistory(base?)无法控制服务器hash 后路径不发送给服务器
createMemoryHistory(base?)SSR、Node 测试不读写浏览器 URL,也不会自动完成初始导航

Memory history 在 SSR 中需要手动 router.push(requestUrl),再等待 router.isReady()。客户端初始导航也是异步的;依赖首个 route 完成后再挂载时,应等待 isReady()。

404 与服务端 fallback 是两层 ​

catch-all 只处理应用已经加载后的未知 URL。若服务器对 /users/42 直接返回自己的 404,Vue Router 根本没有运行。生产服务应先区分 /api/**、真实资源和前端页面路径,再只对页面路径返回 index.html;最终由 catch-all 显示应用 404,并设置合适的服务端状态/SEO 策略。

失败路径 ​

  • 用旧的 Router 3 catch-all *:Router 4 要使用自定义参数正则。
  • 给两条 route record 使用同一个 name:名称应全局唯一,后加入记录可能替换解析目标。
  • 把数字正则当数据校验:匹配成功只证明 URL 形状,服务端仍要验证资源和权限。
  • 只测试站内点击:深链刷新、base 路径和服务器 fallback 仍可能失败。
  • 写极端正则并与重复参数组合:可能产生灾难性回溯;保持模式简单并测试长输入。

练习:文件路由表 ​

配置 /files/:path+(至少一段)、/reports/:year(\\d{4})/:month(\\d{2})? 和 catch-all。要求只用 createMemoryHistory() 与 router.resolve() 验证:文件 path 是数组;合法年份命中 report;非法年份进入 404;命名生成两段文件路径得到正确 href。

变化题:解释部署到 /admin/ 子路径时 base 放在哪里,以及为什么只改 Router 还不够。

参考答案:第 01 题。

本页结论 ​

route record 负责结构匹配,history 负责位置历史,服务器负责把深链交给应用。三者任何一层缺失,站内点击成功都不能证明路由可用。

用心记录每一步成长