路由系统
移动端路由由三部分组成:
@uni-helper/vite-plugin-uni-pages扫描页面文件,生成src/pages.json和virtual:uni-pages。- 页面内通过
definePage()声明页面配置。 uni-mini-router读取生成后的页面配置,提供编程式导航和路由守卫。
pages.json 如何生成?
项目没有手写完整的 pages.json。核心配置在两个地方:
| 文件 | 作用 |
|---|---|
vite.config.ts | 注册 UniPages(),配置类型声明、分包目录和排除规则 |
pages.config.ts | 配置 globalStyle、tabBar 等全局页面配置 |
vite.config.ts 中的配置:
ts
UniPages({
dts: "src/types/uni-pages.d.ts",
subPackages: ["src/subPages"],
exclude: ["**/components/**/*.*"],
})含义:
| 配置 | 说明 |
|---|---|
dts | 生成页面类型声明,方便 TypeScript 识别路由 |
subPackages | 分包页面目录,当前约定为 src/subPages |
exclude | 排除组件目录,避免组件被误识别成页面 |
pages.config.ts 负责全局配置,例如导航栏、下拉刷新距离、TabBar 页面路径等。
注意
src/pages.json 是插件生成文件,文件中有 GENERATED BY UNI-PAGES 标记。新增页面或修改页面标题、布局时,优先改页面里的 definePage() 或 pages.config.ts,不要手动维护生成结果。
新增页面怎么做?
在 src/pages/ 下创建页面文件即可,例如:
text
src/pages/work/user/index.vue插件会自动生成页面路径:
text
/pages/work/user/index页面配置写在 <script setup> 中的 definePage():
vue
<script setup lang="ts">
definePage({
name: "user",
style: {
navigationBarTitleText: "用户管理",
},
})
</script>常用配置:
| 配置 | 说明 |
|---|---|
name | 页面名称,便于识别和调试 |
style.navigationBarTitleText | 原生导航栏标题 |
style.navigationStyle | 导航栏样式,custom 表示自定义导航栏 |
layout | 页面布局,不写时使用默认布局 |
meta.requireAuth | 是否需要登录后访问,路由守卫会读取 |
需要登录的页面可以声明 meta.requireAuth:
ts
definePage({
name: "profile",
style: { navigationBarTitleText: "个人资料" },
meta: { requireAuth: true },
})默认 layout 是什么?
项目使用 @uni-helper/vite-plugin-uni-layouts 管理布局,布局文件在:
text
src/layouts/
├── default.vue
└── tabbar.vue默认规则:
| 页面配置 | 实际布局 | 适用场景 |
|---|---|---|
不写 layout | default | 普通页面、详情页、表单页 |
layout: "tabbar" | tabbar | 首页、工作台、我的等底部 TabBar 页面 |
layout: false | 不套布局 | 登录页、引导页、需要完全自定义结构的页面 |
普通页面不需要显式写 layout: "default":
ts
definePage({
name: "user",
style: { navigationBarTitleText: "用户管理" },
})TabBar 页面需要显式声明:
ts
definePage({
name: "home",
style: { navigationStyle: "custom" },
layout: "tabbar",
})登录页如果不想套默认布局,可以显式关闭:
ts
definePage({
name: "login",
style: { navigationStyle: "custom", navigationBarTitleText: "" },
layout: false,
})建议
新增业务页面大多数情况下不用写 layout,只写 name 和 style.navigationBarTitleText 即可。只有底部导航页面、登录页、全屏页或特殊页面才需要关心 layout。
路由如何进入 uni-mini-router?
src/router/index.ts 从 virtual:uni-pages 读取生成后的页面配置:
ts
import { pages, subPackages } from "virtual:uni-pages";项目会把主包和分包页面转换成 uni-mini-router 的路由表:
ts
function generateRoutes() {
const routes = pages.map((page) => ({
...page,
path: `/${page.path}`,
meta: page.meta ?? undefined,
}));
subPackages?.forEach((subPackage) => {
const subRoutes = subPackage.pages.map((page) => ({
...page,
path: `/${subPackage.root}/${page.path}`,
meta: page.meta ?? undefined,
}));
routes.push(...subRoutes);
});
return routes;
}所以 definePage() 中的 meta 会透传到路由守卫中。
页面跳转
ts
// 保留当前页
uni.navigateTo({ url: "/pages/work/user/index" });
// 不保留当前页
uni.redirectTo({ url: "/pages/login/index" });
// 关闭所有页面
uni.reLaunch({ url: "/pages/index/index" });
// 编程式导航
router.push({ path: "/pages/mine/profile/index" });参数传递
ts
uni.navigateTo({ url: `/pages/detail/index?id=${id}&type=${type}` });
onLoad((options) => {
const { id, type } = options;
});复杂对象不要直接拼到 URL,可以用全局状态、缓存或事件传递。
常见问题
| 问题 | 原因 | 处理方式 |
|---|---|---|
| 新页面跳转 404 | 页面路径没有被插件扫描到 | 确认文件在 src/pages 或 src/subPages 下,且不在 components 目录 |
改了 definePage() 不生效 | 生成文件或开发服务未刷新 | 重启开发服务后再看生成的 src/pages.json |
| 页面没有底部 TabBar | 没写 layout: "tabbar" | TabBar 页面在 definePage() 中显式声明 |
| 页面出现不期望的外层布局 | 默认套了 default 布局 | 特殊页面可写 layout: false |
| 路由守卫不生效 | 没有配置 meta.requireAuth | 在 definePage() 中补充 meta: { requireAuth: true } |
