uni-simple-router 是替代 uni-app 原生路由的稳定方案,需配合 uni-read-pages 读取 pages.json;配置 routes、区分 params/query、异步守卫用 async/await、h5 用 routermount、非 h5 用 app.$mount,且须全链路跨平台兼容。

uni-app 原生路由不支持全局守卫、参数解耦、跨平台统一 API,直接用 uni.navigateTo 或 pages.json 配置会很快遇到权限控制难、H5 和小程序跳转逻辑分裂、页面传参易出错等问题。uni-simple-router 是目前最稳定、维护活跃的替代方案,它不是“增强版 uni-app 路由”,而是用 Vue Router 语义重构了整个导航体系——但前提是配置不能照搬 Vue Router 那套。
安装和基础配置必须配合 uni-read-pages
uni-simple-router 本身不读取 pages.json,必须靠 uni-read-pages 把页面配置转成路由数组。漏掉这步,router.push('/pages/login/login') 会白屏或报 Route not found 错误。
- 执行
npm install uni-simple-router uni-read-pages(两个都要装) - 在项目根目录新建
vue.config.js,按官方要求注入ROUTES变量,关键点是includes至少包含['path', 'name'],否则router.beforeEach拿不到to.name -
router.js中创建路由时,routes字段必须写成[ROUTES],不是手动写数组,也不是从pages.json直接 import - 注意
platform参数要和环境变量一致:process.env.VUE_APP_PLATFORM通常设为'h5'、'mp-weixin'或'app',否则动画、跳转行为会异常
router.push 传参必须区分 params 和 query
uni-app 的 URL 规则和 Web 不同:params 对应路径占位符(如 /detail/:id),query 对应 URL 查询字符串(如 ?id=123&type=good)。混用会导致 H5 正常但小程序跳转失败,或参数在 onLoad 里收不到。
- 路径带动态段:用
router.push({ path: '/detail/:id', params: { id: '1001' } }),此时目标页onLoad收不到id,得在onShow里通过getCurrentPages()手动取 - 传查询参数:用
router.push({ path: '/detail', query: { id: '1001', type: 'good' } }),这样onLoad能直接拿到options.id - 别写
router.push('/detail?id=1001')这种字符串形式——H5 可能 work,但小程序会忽略 query,且无法触发beforeEach守卫
全局守卫里不能直接调用 uni.showLoading 等同步 API
router.beforeEach 是同步钩子,但 uni.showLoading、uni.getStorage 这些 API 是异步的。常见错误是写成:
router.beforeEach((to, from, next) => {
const token = uni.getStorageSync('token') // ❌ 同步读取可能为空
if (!token) next('/login')
else next()
})
实际应该用 async/await + next 的回调形式,且必须等异步完成再调 next:
router.beforeEach(async (to, from, next) => {
try {
const res = await uni.getStorage({ key: 'token' })
if (res.data) next()
else next('/login')
} catch {
next('/login')
}
})
- 所有涉及 storage、网络请求、扫码等异步操作,都必须包裹在
try/catch里,否则错误会静默吞掉,页面卡死 -
next(false)会中断导航,next('/xxx')是重定向,next()是放行——三者不能混用,尤其不要在catch里漏写next - H5 端守卫可访问
window.location,但小程序端不可,守卫逻辑要严格跨平台兼容
main.js 挂载方式 H5 和非 H5 必须分开处理
这是最容易导致白屏的配置点:RouterMount 只对 H5 生效,而 app.$mount() 对小程序和 APP 生效。写反了,H5 页面空白,小程序报 Cannot read property 'parentNode' of null。
- H5 端必须用
RouterMount(app, router, '#app'),且不能同时调app.$mount() - 非 H5 端(小程序、APP)必须用
app.$mount(),且不能调RouterMount - 条件编译要写完整:
// #ifdef H5和// #ifndef H5不能只写一个,也不能用process.env.NODE_ENV判断——uni-app 编译期只认平台标识 - 如果用了 Pinia 或其他插件,
app.use(router)必须在app.use(store)之后,否则守卫里拿不到 store 实例
真正麻烦的不是写几个 router.push,而是守卫里异步逻辑的收敛、多端参数解析的一致性、以及挂载时机这种“看不见却致命”的细节。哪怕配置全对,pages.json 里少写一个 aliasPath,或者 vue.config.js 里 ROUTES 没暴露 meta 字段,都会让 to.meta.requiresAuth 变成 undefined——问题不在代码,而在配置链路的完整性。










