不少刚开始用Vue Router搭配TypeScript开发的同学,总会碰到「RouteRecordRaw」这个词,它到底是干啥的?写路由配置时怎么正确用它?今天咱们就把这些疑问掰碎了聊清楚~
RouteRecordRaw到底是什么?
简单说,RouteRecordRaw是Vue Router里用来描述「路由记录原始结构」的类型(TypeScript环境下),路由系统要把我们写的路由配置,转换成能识别的规则去匹配URL、渲染组件,RouteRecordRaw就是给这份「原始配置」定规矩的——规定每个路由项得有哪些字段、每个字段是什么格式。
举个例子,你写一个路由对象 { path: '/home', name: 'Home', component: HomeView } ,它的类型就是RouteRecordRaw,要是用TypeScript,定义路由数组时写 const routes: RouteRecordRaw[] = [] ,TypeScript就会帮你检查每个路由项:path格式对不对?name是不是字符串?component有没有正确引入?避免你把component写成components、path写成paths这类低级错误。
不用RouteRecordRaw会怎样?
如果不用这个类型约束,相当于给路由配置“裸奔”,比如你不小心把component写成components,VSCode不会报红提醒,直到运行项目时才发现页面不渲染、路由跳转失效,这时候debug要花很多时间找哪里写错了。
而用了RouteRecordRaw,写代码时TypeScript就像个“实时检查员”,一旦字段名、格式不对,立刻标红提醒,相当于把很多运行时才会暴露的错误,提前到编码阶段解决,能省不少调试精力。
怎么用RouteRecordRaw写路由配置?
下面分几种常见路由场景,看看具体怎么配:
(1)基础静态路由
最基础的路由长这样:
import { RouteRecordRaw } from 'vue-router'
import HomeView from '../views/HomeView.vue'
const routes: RouteRecordRaw[] = [
{
path: '/',
name: 'home',
component: HomeView
}
]
这里要注意3个核心字段:path(路由路径)、name(路由命名,可选但建议写,方便编程式导航)、component(对应的页面组件),RouteRecordRaw会检查这几个字段的类型和格式,比如path必须是字符串,component必须是组件或异步加载函数。
(2)动态路由(带参数)
如果要做用户详情页,需要通过/user/123这种路径传ID,路由配置得这么写:
const routes: RouteRecordRaw[] = [
{
path: '/user/:id', // 动态段用:id表示
name: 'user',
component: () => import('../views/UserView.vue') // 也可以用懒加载
}
]
RouteRecordRaw对path的动态参数格式有约束,必须用:参数名的形式,要是你写成/user_id/:id(多了下划线),TypeScript会提示“类型不匹配”,提前拦掉这种格式错误。
(3)嵌套路由(children)
比如有个Dashboard布局页,里面要嵌套Overview、Analysis等子页面,路由得嵌套着写:
const routes: RouteRecordRaw[] = [
{
path: '/dashboard',
component: () => import('../views/DashboardLayout.vue'),
children: [
{
path: 'overview', // 注意:子路由path不用加/,是相对父路由的路径
component: () => import('../views/OverviewView.vue')
},
{
path: 'analysis',
component: () => import('../views/AnalysisView.vue')
}
]
}
]
这里children本身也是RouteRecordRaw的数组,所以每个子路由项也要符合结构要求,而且子路由的path是相对父路由的,比如父路由是/dashboard,子路由写overview,最终匹配的是/dashboard/overview,要是你给子路由path加了(写成/overview),就会变成绝对路径,导致匹配错误,这时候RouteRecordRaw不会拦(因为格式没毛病),但逻辑会错,得自己注意。
(4)重定向(redirect)和别名(alias)
如果要把旧路径重定向到新路径,或者给路径起别名,配置长这样:
const routes: RouteRecordRaw[] = [
{
path: '/old-path',
redirect: '/new-path' // 重定向
},
{
path: '/main',
alias: '/index' // 别名,访问/index也能打开/main的页面
}
]
RouteRecordRaw里内置了redirect和alias的类型定义,写的时候要注意字段名别拼错(比如把redirect写成redirct),否则TypeScript会立刻报错。
RouteRecordRaw和路由实例化有啥关系?
当我们用createRouter创建路由实例时,需要传入routes配置:
import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes // 这里的routes必须是RouteRecordRaw[]类型
})
Router构造函数内部会把这些「原始路由记录」(RouteRecordRaw)转换成内部路由对象——处理path解析、组件加载逻辑(比如懒加载的import)、嵌套路由关系等,所以RouteRecordRaw是“原材料”,路由系统加工后变成能工作的“成品”,用来匹配URL、渲染组件。
结合懒加载时要注意啥?
很多项目为了优化首屏加载速度,会用路由懒加载,
component: () => import('../views/AboutView.vue')
RouteRecordRaw对这种异步加载函数的支持很好,类型上是兼容的,但要注意2个点:
- ① 导入路径别写错:比如少写.vue后缀(如果是Vue单文件组件),TypeScript可能不会报错(因为路径解析由Vite/Webpack这类构建工具处理),但运行时会报“找不到模块”,所以写懒加载时,路径要仔细核对,比如确认是
../views/AboutView.vue而不是../view/AboutView.vue(少了个s)。 - ② 动态导入的组件要存在:如果团队协作时,有人删了AboutView.vue文件,TypeScript也没法提前发现(因为是运行时加载),所以最好配合Git钩子、代码审查来避免这种情况。
能给RouteRecordRaw加自定义字段吗?
当然可以!比如我们想给路由加个title(页面标题)、requiresAuth(是否需要登录)这类自定义信息,通常放在meta里:
// 先扩展RouteMeta类型(Vue Router内置的meta类型)
declare module 'vue-router' {
interface RouteMeta {: string;
requiresAuth?: boolean;
}
}
const routes: RouteRecordRaw[] = [
{
path: '/profile',
component: () => import('../views/ProfileView.vue'),
meta: {
title: '个人中心',
requiresAuth: true
}
}
]
如果想加meta以外的自定义字段,比如给每个路由加个customTag,可以这样扩展RouteRecordRaw:
declare module 'vue-router' {
interface RouteRecordRaw {
customTag?: string;
}
}
const routes: RouteRecordRaw[] = [
{
path: '/special',
component: SpecialView,
customTag: 'vip' // 现在可以正常写自定义字段了
}
]
这样扩展后,TypeScript就允许RouteRecordRaw有customTag字段,既保持类型约束,又满足业务定制需求。
常见错误场景咋解决?
实际开发中,这些错误很常见,提前避坑能省很多事:
(1)字段名拼写错误
比如把component写成components,VSCode会立刻报红:“类型"{ path: string; name: string; components: ... }"不符合RouteRecordRaw的结构”,解决方法很简单——检查字段名,改成正确的component。
(2)动态路由参数格式错
如果把/user/:id写成/user_id/:id(多了下划线),TypeScript会提示“类型字符串不符合路由路径规则”,这类错误属于格式问题,修正path的动态段写法就行,比如改成/user/:id。
(3)懒加载路径错误
假设要加载AboutView.vue,却写成import('../views/AbotView.vue')(拼写错),TypeScript可能不会报错(因为路径是字符串,TS没法判断文件是否存在),但运行时会404,解决方法是写完路径后,手动检查一遍,或者配合IDE的路径自动补全功能。
(4)嵌套路由path写绝对路径
父路由是/dashboard,子路由写成path: '/overview',这会让子路由匹配/overview而不是/dashboard/overview,导致页面不显示,RouteRecordRaw不会拦这种逻辑错误,所以写嵌套路由时,子路由path别加/ ,保持相对路径。
实战:从0到1配个TS路由
假设现在要新建一个Vue 3 + TypeScript + Vue Router 4的项目,完整的路由配置流程是这样的:
步骤1:安装依赖
打开终端,执行:
npm install vue-router@4
步骤2:创建路由文件
在src目录下新建router/index.ts如下:
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
// 引入静态组件
import HomeView from '../views/HomeView.vue'
const routes: RouteRecordRaw[] = [
// 基础路由
{
path: '/',
name: 'home',
component: HomeView
},
// 带命名的路由
{
path: '/about',
name: 'about',
component: () => import('../views/AboutView.vue') // 懒加载
},
// 动态路由
{
path: '/user/:id',
name: 'user',
component: () => import('../views/UserView.vue')
},
// 嵌套路由
{
path: '/dashboard',
component: () => import('../views/DashboardLayout.vue'),
children: [
{
path: 'overview',
component: () => import('../views/OverviewView.vue')
},
{
path: 'analysis',
component: () => import('../views/AnalysisView.vue')
}
]
},
// 重定向
{
path: '/old',
redirect: '/new'
},
// 带meta的路由
{
path: '/profile',
component: () => import('../views/ProfileView.vue'),
meta: {
title: '个人中心',
requiresAuth: true
}
}
]
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes
})
export default router
步骤3:在main.ts里挂载路由
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(router)
app.mount('#app')
这样一套配置下来,每个路由项都被RouteRecordRaw约束着,TypeScript会帮你检查大部分错误,比如要是把component写成components,VSCode会立刻标红,提醒你字段错误。
RouteRecordRaw是路由的“安全网”
对Vue Router+TypeScript项目来说,RouteRecordRaw不是额外的负担,而是保证路由配置规范、减少错误的重要工具,它像个“安全网”,在你写路由时提前拦住字段拼写、格式这类低级错误,让路由系统更稳定。
刚开始接触可能觉得类型约束有点麻烦,但熟悉后会发现——它帮你省的调试时间,远比写类型的那点功夫多,尤其是团队协作时,统一用RouteRecordRaw约束路由配置,能减少很多“为什么我这路由不生效”的沟通成本~
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
code前端网


发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。