更新日志
本项目的变更记录遵循 Keep a Changelog 与 语义化版本。
[2.7.1] - 2026-08-31
修复
- H5 端返回死循环("无法正常返回,一直来回闪烁") - 修复
onBeforeBack在 H5 平台的 popstate 返回守卫导致相邻页面间死循环闪烁的问题(issue #39)- 现象:H5 端按 首页 → 二级 → 三级 进入后,在三级页执行返回(
router.back()或浏览器后退)时,页面在二、三级之间高频反复切换、无法正常返回,控制台无 JS 报错 - 根因:H5 返回守卫原采用「
history.go(1)撤销后退 → 守卫放行后navigateBack重新后退」策略;navigateBack在 H5 上会触发多次 popstate,当这些自身 popstate 因派发时机滞后被误判为"新的外部后退"时,会再次进入「撤销 + 重放」分支,形成死循环 - 修复方案:
router.back()及守卫放行后的返回在发起navigateBack前,置位 H5 返回进行中标记,并在时间窗口内放行本次导航产生的所有 popstate(不再进入「撤销 + 重放」分支);同时记录返回目标路径,命中目标 URL 即视为本次返回完成(确定性结束),时间窗口作为兜底自动复位 - 守卫语义保持:守卫放行时正常返回上一页、守卫中止时停留当前页,均不再出现死循环
- 涉及文件:
router/back-guard.ts(H5 返回进行中标记 + 目标命中判定)、router/index.ts(back()前置标记)
- 现象:H5 端按 首页 → 二级 → 三级 进入后,在三级页执行返回(
[2.7.0] - 2026-08-30
新增
- H5 端导航动画(CSS 过渡) - 导航动画能力从 App 端扩展到 H5 平台,通过注入的关键帧 CSS 实现与 App 端
animationType命名对齐的过渡效果(基于transform/opacity)push(uni.navigateTo)成功后对目标页播放进入动画(animatePageEnter),经requestAnimationFrame延后到下一帧以等待页面完成渲染back(uni.navigateBack)先对当前页播放退出动画(animatePageExit),动画结束后再执行真正的返回,使滑出效果与 App 端一致- 支持
slide-in/out-*、fade-in/out、zoom、pop等方向键帧;动画结束(animationend)后自动清理样式,并带定时兜底避免页面快速切换时残留 - 动画时长默认
300ms(DEFAULT_ANIMATION_DURATION),可通过duration覆盖
plugins/animation/h5.ts模块 - H5 动画样式注入(幂等)与进入/退出动画播放逻辑。npm 发布产物由 tsup 构建、不处理#ifdef H5条件编译,故采用运行时getPlatform().isH5平台判断
优化
- 导航动画有效值统一在 router 层计算 -
meta.animation仅在注册AnimationPlugin时注入导航选项,未注册时即使配置meta.animation也不生效;navigate.ts不再内部回退读取meta.animation,与调用时传入animation的PLUGIN_REQUIRED门控保持一致 - 动画平台能力统一 - App 端为原生窗口动画(
animationType),H5 端push/back走 CSS 过渡,小程序端由宿主控制
重构
- 抽出
navigation/helpers/uni-api.ts、plugins/animation/helpers、plugins/interceptor/helpers/parse.ts等助手模块,收敛导航 API 的 uni 调用与平台判断逻辑
[2.6.0] - 2026-08-27
新增
- 全局返回守卫
onBeforeBack- 新增router.onBeforeBack()方法,拦截返回操作(App 物理返回键 / 顶部导航栏返回 /uni.navigateBack,H5 浏览器后退按钮 / 后退手势)- 返回
false阻止返回,true/undefined放行,支持异步(Promise),不受 uni-apponBackPress同步返回限制 - App 端通过全局 mixin 的
onBackPress接入物理返回键 / 导航栏返回 /navigateBack;守卫放行后手动返回,通过内部标记避免递归 - H5 端通过浏览器
popstate事件接入后退,采用「撤销后退 → 执行守卫链 → 守卫放行后重新后退」策略 - 守卫放行后复用
beforeEach→beforeResolve守卫链,中止 / 重定向行为与完整导航一致 - 新增
BackGuard/BackGuardReturn类型 - 平台限制:App / H5 可拦截;iOS 侧滑返回需配合
app.setSideSlipGesture禁用手势;小程序原生返回无法拦截
- 返回
- iOS 侧滑返回手势控制(
app.setSideSlipGesture) - 新增RouterOptions.appApp 平台专属配置,按当前路由动态设置 iOS 侧滑返回手势(对应plus.webview.setStyle({ popGesture }))'none'禁用侧滑返回,使侧滑返回走守卫链(onBeforeBack生效)'close'开启原生侧滑返回,保留原生手势体验(侧滑绕过守卫)- 由全局 mixin 在页面
onShow时自动调用,仅 iOS 平台生效 - 新增
AppRouterOptions/SideSlipGesture类型
getPlatform()平台判断工具 - 统一平台判断入口,基于uni.getSystemInfoSync()并带缓存- 返回
PlatformInfo:isApp/isH5/isMp/isIOS/isAndroid/uniPlatform/osName - 兼容旧版本:
uniPlatform缺失时回退到typeof plus/typeof window推断 App / H5 - 新增
plus全局对象与uni.getSystemInfoSync()类型声明
- 返回
优化
- 平台判断统一 - InterceptorPlugin 的
isWebPlatform()改用getPlatform().isH5,消除散落的typeof window/typeof document特殊判断
[2.5.0] - 2026-08-23
新增
- RouterLink H5 端渲染为原生
<a>标签 - 恢复浏览器链接的原生能力(语义化、右键新标签页、地址识别、无障碍、href 原生行为)- H5 端通过
#ifdef H5条件编译渲染为<a :href>,href由useLink响应式提供;普通左键preventDefault后交由路由器导航,守卫链照常生效 - 修饰键(Ctrl/Cmd/Shift/Alt)或中键点击保留浏览器原生行为(如新标签页打开)
href自动适配 hash 路由(#前缀),确保右键"在新标签页打开"能正确路由- 其他平台(App/小程序)渲染为
<navigator>(uni-app 原生导航组件),行为不变 - 脚本中修饰键判断与 hash 前缀逻辑使用
#ifdef H5条件编译,非 H5 平台编译期剔除,避免非 H5 事件对象无button属性导致导航被误拦截
- H5 端通过
[2.4.0] - 2026-08-21
新增
- 可控重定向(Controllable Redirect) - 守卫返回值模式补全重定向方式控制能力,通过返回
{ location, mode }对象可显式指定重定向使用的导航方式- 新增
NavigationRedirect接口,扩展NavigationGuardReturn类型(增加| NavigationRedirect分支) mode支持'push'(uni.navigateTo)/'replace'(uni.redirectTo)/'relaunch'(uni.reLaunch)- 重定向方式优先级:显式
mode> 原始导航方式 >back回退relaunch mode缺省时行为不变(沿用原始导航方式),完全向后兼容guardRoute()冷启动场景同步支持可控重定向- 示例:
- 新增
typescript
router.beforeEach((to, from) => {
if (to.meta.requireAuth && !isLoggedIn()) {
// 用 replace 跳转登录页,避免登录页残留在页面栈中
return { location: { name: 'login', query: { redirect: to.fullPath } }, mode: 'replace' }
}
})修复
- 字符串路径含 query 时注入内部 key 产生双
?-injectQueryKey对已含 query 的字符串路径(如'/detail?id=1')注入__nav_id/__params_key时未拆分已有 query,导致拼接出?id=1?__nav_id=...的畸形 URL- 修复:字符串路径先按
?拆分为 path + 已有 query,再合并注入,最终为?id=1&__nav_id=... - 同时惠及 ChannelPlugin(
__nav_id)与 ParamsPlugin(__params_key)
- 修复:字符串路径先按
[2.3.1] - 2026-08-21
修复
- RouterLink 组件 H5 端控制台错误 - 将根元素从
<navigator>替换为<view>,解决 H5 端每次点击时 uni-h5 输出[ERROR] <navigator/> should have url attribute控制台错误的问题<view>同样支持hover-class/hover-stop-propagation/hover-start-time/hover-stay-time等点击态属性- 实际导航完全由
@click.stop="handleClick"调用路由器 API 完成,不影响导航功能
优化
- 组件 emits 类型重构 - 将
RouterLinkEmits、TabBarEmits从interface改为type别名,与其他类型定义风格保持一致
[2.3.0] - 2026-08-19
新增
useLink组合式 API - 暴露 RouterLink 内部行为为组合式函数,用于构建自定义导航组件- 与 Vue Router 4.x 的
useLink行为一致,返回响应式的路由信息、匹配状态和导航方法 - 返回值:
route(解析后的路由)、href(目标路径)、isActive(是否匹配)、isExactActive(是否完全匹配)、navigate(执行导航) - 示例:
- 与 Vue Router 4.x 的
typescript
import { useLink } from '@meng-xi/uni-router'
const { href, isActive, navigate } = useLink({
to: { name: 'pagesDetailDetail', query: { id: '1' } }
})
// 响应式绑定
const classes = computed(() => ({
'nav-link': true,
'nav-link-active': isActive.value
}))isNavigationFailure工具函数 - 导航失败类型检查工具,替代手动instanceof+code检查
typescript
import { isNavigationFailure, RouterErrorCode } from '@meng-xi/uni-router'
try {
await router.push('/somewhere')
} catch (error) {
if (isNavigationFailure(error, RouterErrorCode.NAVIGATION_DUPLICATED)) {
// 忽略重复导航
}
}UseLinkOptions/UseLinkReturn类型 -useLink的选项和返回值类型
[2.2.0] - 2026-08-18
破坏性变更
- 彻底移除
next()回调模式 - 守卫系统全面采用返回值模式,与 Vue Router 4.x 完全一致- 删除
NavigationGuardNext类型,不再支持(to, from, next)三参数签名 - 删除
NavigationGuardNextOptions类型,next(location, { mode })不再可用 - 删除
runGuardWithNext()函数,移除整个next回调执行路径 - 删除
runGuard()模式检测分发器,由仅支持返回值模式的runGuard()替代 NavigationGuard类型签名从(to, from, next?)改为(to, from)- 守卫仅通过返回值控制导航行为:
return undefined/return true→ 放行return false→ 中止导航(NAVIGATION_ABORTED)return '/login'/return { name: 'login' }→ 重定向return new Error()/throw new Error()→ 取消导航(NAVIGATION_CANCELLED)
- 删除
新增
onBeforeRouteLeave组合式 API - 组件内离开守卫,通过返回值控制离开导航,组件卸载时自动移除守卫- 与 Vue Router 4.x 的
onBeforeRouteLeave行为一致,支持同步和异步守卫 - 示例:
- 与 Vue Router 4.x 的
typescript
import { onBeforeRouteLeave } from '@meng-xi/uni-router'
// 同步离开确认
onBeforeRouteLeave(() => {
if (hasUnsavedChanges) {
return false
}
})
// 异步确认对话框
onBeforeRouteLeave(() => {
if (hasUnsavedChanges) {
return new Promise(resolve => {
uni.showModal({
title: '确认离开',
content: '有未保存的修改,确定要离开吗?',
success: res => resolve(res.confirm)
})
})
}
})RouteLeaveGuard类型 - 组件内离开守卫函数类型,与NavigationGuard返回值一致
重要限制
onBeforeRouteLeave 只能拦截经过路由器的导航(push / replace / back / relaunch),无法拦截物理返回键、侧滑返回手势、浏览器后退按钮、小程序左上角返回按钮等场景。
迁移指南
- 将
(to, from, next) => { next() }改写为(to, from) => { return } next(false)→return falsenext({ name: 'login' })→return { name: 'login' }next({ name: 'login' }, { mode: 'replace' })→return { name: 'login' }(mode不再支持,重定向方式沿用原始导航方式)
[2.1.0] - 2026-08-16
新增
- 守卫返回值模式(Vue Router 4.x 兼容) - 守卫全面支持通过返回值控制导航行为,无需调用
next()回调return undefined/return true— 放行return false— 中止导航(NAVIGATION_ABORTED)return RouteLocationRaw— 重定向return Error/throw Error— 取消导航(NAVIGATION_CANCELLED)return { location, mode }— 重定向 + 指定导航方式
NavigationGuardReturn类型 - 守卫返回值类型,支持void | undefined | boolean | RouteLocationRaw | Error | nullafterEach接收failure参数 - 后置钩子第三个参数failure在导航失败时传入,可用于区分成功/失败导航
优化
- 守卫模式自动检测 - 通过函数参数个数自动识别模式:
(to, from, next)三个参数→回调模式(兼容旧版),(to, from)两个参数→返回值模式(推荐) - 混用警告 - 同时使用
next()回调和返回值时,控制台输出警告提示
兼容性
next()回调模式保持完全兼容,标记为已弃用- 旧版守卫代码无需修改即可继续使用
[2.0.0] - 2026-07-13
新增
- 插件架构 - 核心功能拆分为按需注册的插件,未注册的插件不增加包体积和运行时开销
RouterPlugin接口 - Swiper.js 风格的插件系统,通过install(context, options)注册 hookPluginContext接口 - 路由器暴露给插件的 hook 注册 API,支持 7 种生命周期 hookRouterOptions.plugins- 插件注册配置项,传入插件数组即可启用对应功能PLUGIN_REQUIRED错误码 - 使用未注册插件的功能时抛出,帮助快速定位问题
- ParamsPlugin - 页面参数传递插件(从核心拆分)
push/replace/relaunch支持params参数传递复杂数据,不暴露在 URL 中- 参数持久化存储
persistent,H5 刷新后仍可读取 RouterOptions.paramsPersistent全局默认值
- ChannelPlugin - 页面间通信插件(从核心拆分并增强)
useUniEventChannel选项 - 启用后所有导航方式(push/replace/relaunch)均支持eventChannelUniEventChannel类 - 基于uni.$emit/$on/$off/$once全局事件总线实现,替代仅 push 可用的原生 EventChannel- Sticky 事件缓存机制 -
emit()始终缓存事件参数,on()/once()注册时异步触发已缓存事件,解决时序竞态 usePageChannel()组合式 API - 目标页面获取通信通道的便捷方法noopChannel导出 - 空操作通道,无__navId时返回,避免空指针
- InterceptorPlugin - uni API 拦截插件(从核心拆分)
RouterOptions.interceptUniApi选项需要此插件才能生效- 拦截
navigateTo/redirectTo/switchTab/reLaunch/navigateBack,统一守卫流程
- AnimationPlugin - 导航动画插件(从核心拆分)
push/replace/back支持动画参数,仅 App 端生效- 路由级
meta.animation默认动画配置
applySyncHooks导航预处理 - 在setCurrentRoute前执行routeSyncHooks,将__nav_id等内部 key 从 query 提取到 params,确保目标页onLoad/<script setup>时usePageChannel()能正确获取通道
优化
syncRoute去重优化 - 比较前先执行runSyncHooks移除 URL query 中的内部 key(如__nav_id、__params_key),避免因内部 key 差异导致onShow每次触发多余的onRouteChange事件- 路由位置解析逻辑集中 -
router/index.ts中的resolveLocation/extractParamsKey等逻辑提取到utils/route.ts,消除与router/location.ts的重复 - 插件间数据共享 -
pluginData: Record<string, any>在导航流程各阶段间传递,插件通过约定 key 存取数据,避免直接耦合
破坏性变更
createRouter必须显式注册插件 -params/events/animation/interceptUniApi功能不再默认可用,需在plugins数组中注册对应插件
typescript
// 1.x - 功能默认可用
const router = createRouter({ routes, interceptUniApi: true })
// 2.0 - 需要显式注册插件
const router = createRouter({
routes,
plugins: [ParamsPlugin, ChannelPlugin, InterceptorPlugin, AnimationPlugin],
interceptUniApi: true
})@meng-xi/uni-router/plugins子路径导出 - 插件从主入口@meng-xi/uni-router和子路径@meng-xi/uni-router/plugins均可导入- 未注册插件功能抛出
PLUGIN_REQUIRED- 使用params但未注册 ParamsPlugin、使用events但未注册 ChannelPlugin、使用animation但未注册 AnimationPlugin、设置interceptUniApi: true但未注册 InterceptorPlugin 时,均抛出PLUGIN_REQUIRED错误
迁移指南
- 在
createRouter中添加plugins数组,按需注册功能插件 - 从
@meng-xi/uni-router导入插件:import { ParamsPlugin, ChannelPlugin, InterceptorPlugin, AnimationPlugin } from '@meng-xi/uni-router' usePageChannel()从@meng-xi/uni-router主入口导入- uni_modules 版本从
./uni_modules/mxuni-router-v2/js_sdk/index.js导入
[1.11.0] - 2026-07-10
新增
- TabBar / TabBarItem 组件 - 自定义底部导航栏,需配合使用
- TabBar Props:
color/selectedColor/bgColor/borderStyle/fixed/border/placeholder/safeAreaInsetBottom/zIndex/beforeChange - TabBar Events:
change(item, index)/error(error) - TabBarItem Props:
to/text/iconPath/selectedIconPath/dot/badge/badgeMax/badgeColor/replace - TabBarItem Slots:
#icon="{ active }"自定义图标、default自定义文字 - 内置徽标系统:
dot小红点(优先级高于 badge)、badge数字/文字徽标、badgeMax上限、badgeColor自定义颜色 beforeChange拦截器:返回false或 reject 阻止切换,支持异步
- TabBar Props:
- SCSS 主题定制 - 组件样式迁移到 SCSS,支持双层级覆盖
- SCSS 变量
!default:编译时覆盖(通过 vitecss.preprocessorOptions.scss.additionalData) - CSS 自定义属性:运行时覆盖(在父元素设置
--mx-tabbar-*/--mx-tabbar-item-*) - TabBar 变量:
--mx-tabbar-height/--mx-tabbar-background/--mx-tabbar-border-color - TabBarItem 变量:
--mx-tabbar-item-icon-size/--mx-tabbar-item-font-size/--mx-tabbar-item-gap/--mx-tabbar-badge-color/--mx-tabbar-badge-dot-size/--mx-tabbar-badge-font-size/--mx-tabbar-badge-min-width/--mx-tabbar-badge-line-height/--mx-tabbar-badge-padding
- SCSS 变量
TabBarItemProps类型导出 - 从@meng-xi/uni-router主入口新增导出,用于 TabBarchange事件回调类型标注
优化
- 组件目录按 easycom 规范重构 - 组件从扁平文件改为
components/<name>/<name>.vue嵌套结构,符合 easycom 自动注册约定components/RouterLink.vue→components/router-link/router-link.vuecomponents/TabBar.vue→components/tab-bar/tab-bar.vuecomponents/TabBarItem.vue→components/tab-bar-item/tab-bar-item.vue- 共享上下文
tabbar-context.ts→tab-bar/context.ts - 组件类型提取到同级
type.ts(router-link/type.ts、tab-bar/type.ts)
- uni_modules 版本组件导入改为本地 js_sdk - mxuni-router 包内组件从
@meng-xi/uni-router改为相对路径引用../../js_sdk/index,消除对 npm 包的运行时依赖 - uni_modules 版本标签名变更 -
<mxuni-router>改为<RouterLink>(easycom 自动注册) - 组件 TypeScript 类型提取 - 各组件 props/emits 类型提取到同级
type.ts,共享上下文(InjectionKey + 接口)放在context.ts - 组件 CSS → SCSS - RouterLink、TabBar、TabBarItem 样式全部迁移到 SCSS,使用变量和自定义属性
迁移说明
npm 用户需更新组件导入路径:
| 旧路径 | 新路径 |
|---|---|
@meng-xi/uni-router/components/RouterLink.vue | @meng-xi/uni-router/components/router-link/router-link.vue |
@meng-xi/uni-router/components/TabBar.vue | @meng-xi/uni-router/components/tab-bar/tab-bar.vue |
@meng-xi/uni-router/components/TabBarItem.vue | @meng-xi/uni-router/components/tab-bar-item/tab-bar-item.vue |
uni_modules 用户无需修改,easycom 自动注册 <RouterLink> / <TabBar> / <TabBarItem>。
[1.10.0] - 2026-07-09
新增
- 内置页面间通信管理器 - 新增
useUniEventChannel选项与UniEventChannel类,基于uni.$emit/$on/$off/$once全局事件总线实现,替代uni.navigateTo原生 EventChannel,使所有导航方式(push/replace/relaunch)均支持页面间双向通信RouterOptions.useUniEventChannel?: boolean(默认false)- 启用后所有导航方式使用内置通信管理器;默认false时仅push使用uni.navigateTo原生 EventChannel,其他方式不支持页面通信UniEventChannel类 - 实现EventChannel接口,提供emit/on/once/off方法;每次导航生成唯一navigationId(格式nav-<timestamp>-<seq>),通过wrapEventName()包装为uni-router:{navId}:{eventName}隔离事件通道,避免多导航间事件串扰__nav_id通过 URL query 传递,目标页面syncCurrentRoute时读取并重建通道,H5 刷新后仍可恢复通信- 新增
noopChannel导出 - 空操作通道,所有方法均为 no-op 并返回自身;usePageChannel()在无__navId时返回noopChannel,避免空指针
- Sticky 事件缓存机制 -
emit()始终将事件参数缓存到pendingEvents,on()/once()注册监听器时异步触发已缓存事件(不删除缓存),解决发送方emit与目标页setup注册监听的时序竞态- 适用场景:发起页导航后立即
emit,目标页setup中on监听时仍能收到缓存事件 - 缓存随
UniEventChannel.destroy()清理(页面onUnmounted时自动调用)
- 适用场景:发起页导航后立即
usePageChannel()组合式 API - 目标页面获取通信通道的便捷方法- 读取
route.params.__navId,返回对应的UniEventChannel实例;无__navId时返回noopChannel onUnmounted()时自动调用destroyChannel(navId)清理监听器与缓存,避免内存泄漏
- 读取
NavigationResult返回类型 -push/replace/relaunch返回值从RouteLocation扩展为NavigationResult(继承RouteLocation,新增可选eventChannel?: EventChannel)- 默认模式:仅
push(对应uni.navigateTo)的eventChannel可用 useUniEventChannel: true:所有导航方式均返回内置UniEventChannel- 类型向后兼容:
NavigationResult extends RouteLocation,原const route: RouteLocation = await router.push(...)仍可用
- 默认模式:仅
- 通道注册表(内部) -
registerChannel/getOrCreateChannel/getRegisteredChannel/hasChannel/destroyChannel管理navId → UniEventChannel映射registerChannel采用 first-wins 策略:同一navId已存在通道时返回 false,避免重复注册getOrCreateChannel优先复用已注册通道,无则新建
RouterLink的navigated事件支持所有导航方式 - 配合NavigationResult返回类型,navigate()现对 push/replace/relaunch 统一触发navigated事件并传递eventChannel(默认模式仅 push 有值,useUniEventChannel: true时所有方式均有值);1.9.0 中 replace/relaunch 无eventChannel,仅 push 触发为当时一致行为
优化
RouterLink的eventsprop 与navigated事件 JSDoc 完善 - 明确说明默认模式下events仅push生效、navigated的eventChannel仅push有值;启用useUniEventChannel后所有导航方式均生效
[1.9.0] - 2026-07-06
新增
- 全局 mixin 自动同步路由状态 -
install()中注册app.mixin({ onShow() { router.syncRoute() } }),每个页面onShow时自动同步路由状态,无需在各页面手动调用syncRoute()- mixin 钩子先于组件自身
onShow执行,配合syncRoute()的去重机制(path + query 相同则跳过)避免重复同步 - 应用从后台回到前台时,当前活动页的
onShow会自动触发同步,App.vue的onShow无需手动调用 onLoad早于onShow,若需在onLoad中读取路由信息可手动调用syncRoute()
- mixin 钩子先于组件自身
修复
back()后 params 丢失 -push/replace时实际导航 URL 保留__params_key(route.query中不可见),back()返回原页面后syncCurrentRoute从 URL 读取 key 并用peek重建 params- 问题:
matcher.resolve会从 query 中移除__params_key,导致实际导航 URL 不含 key,back()后无法从 URL 重建 params - 修复:
performNavigation在 resolve 后通过extractParamsKey提取 key,executeNavigation将 key 拼回实际导航 URL 的 query 中;syncCurrentRoute从 URL 读取 key 并用peek(非get)重建 params,避免惰性清理误删
- 问题:
setCurrentRoute执行时机 -setCurrentRoute(to)提前到 uni 导航 API 调用之前执行,确保目标页onLoad/onShow时route.value已是完整目标路由(含name/params)- 问题:此前
setCurrentRoute在 uni API 成功后执行,目标页onLoad/onShow触发时currentRoute仍为来源路由,导致route.value不含目标路由信息 - 修复:在调用
navigateTo/replaceTo/relaunchTo之前调用setCurrentRoute(to);导航 API 失败时回滚到from
- 问题:此前
[1.8.1] - 2026-06-26
修复
interface对象无法赋值给params字段 - 解决 v1.8.0 中router.push({ params })传入interface定义的对象时类型报错的问题- 问题:v1.8.0 中
RouteLocationPathRaw.params/RouteLocationNamedRaw.params的类型为interface ParamObject(带索引签名{ [key: string]: ParamValue })。TypeScript 严格模式下,interface定义的对象类型没有显式索引签名,无法赋值给带索引签名的类型,导致const params: MyInterface = {...}; router.push({ params })报错"缺少类型 'string' 的索引签名" - 修复:新增
ParamsInput类型(object)作为输入侧类型,params字段改用ParamsInput,通过结构子类型兼容任意interface对象;输出侧ParamObject从interface改为type别名(Record<string, ParamValue>),保留索引签名访问 - 设计说明:参考 vue-router 的
RouteParamsRawGeneric(Record<string, RouteParamValueRaw | ...[]>)调研,发现其值类型仅含原始类型(string | number | null | undefined),原始类型属性的interface对象可通过结构子类型兼容Record;而 mxuni-router 的ParamValue包含object/ParamValue[]分支(支持复杂数据传递),此场景下Record<string, ParamValue>在 vue-tsc 严格模式下仍不兼容interface对象,必须使用object - 运行时由
ParamsManager校验 JSON 可序列化性 - 新增
ParamsInput类型导出
- 问题:v1.8.0 中
[1.8.0] - 2026-06-25
新增
- 冷启动守卫检查
guardRoute()- 解决用户通过 H5 URL / 小程序场景值 / App deeplink 直接进入页面时,页面由 uni-app 框架直接加载、不经过路由器导航、守卫(beforeEach 等)未执行的问题Router.guardRoute(location?, options?)- 对指定路由执行守卫链检查(不执行实际导航),按守卫结果决定是否重定向GuardRouteOptions- 选项类型,包含onAbort回调,守卫中止时触发并传入NavigationFailure- 行为:守卫放行 → 不执行导航,resolve 目标路由;守卫重定向 → 按守卫指定方式(默认
relaunch,清空栈避免返回受保护页面)跳转;守卫中止 → 调用onAbort回调并 rejectNavigationFailure - 执行完整守卫链:
beforeEach→beforeEnter→beforeResolve - 典型用法:在
App.vue的onLaunch中router.isReady().then(() => router.guardRoute(undefined, { onAbort: () => router.relaunch('/pages/index/index') }))
UniApiError/UniApiCause类型导出 - 将原本内部的 uni API 错误类型导出,提升NavigationFailure.cause的类型可读性UniApiCause- uni 导航 APIfail回调的错误原因类型({ errMsg: string })UniApiError- 接口,包含api(失败的 API 名称,如navigateTo)和cause(原始错误原因)字段NavigationFailure.cause类型从unknown收紧为UniApiError,仅在NAVIGATION_API_ERROR时存在isUniApiError()改为类型守卫(error is UniApiError),便于instanceof后的类型收窄
优化
ParamValue类型兼容性增强 - 对象分支从递归ParamObject改为object,兼容interface定义的对象类型(它们没有索引签名,无法赋值给{ [key: string]: ... });添加undefined分支,兼容含可选属性的对象(JSON.stringify会自动忽略undefined属性)RouterLink组件重构 - 将 location 计算逻辑提取为computed,无附加选项(animation/events/persistent 均未传)时直接使用to,避免无谓的对象包装- uni API
fail回调类型收紧 -env.d.ts中各导航 API(navigateTo/redirectTo/switchTab/reLaunch/navigateBack)的fail回调参数类型从unknown收紧为UniApiCause
修复
- 守卫混用模式警告 - 当守卫同时调用
next()并返回 Promise 时输出警告(next()之后的异步错误会被静默吞掉,开发者应选择其中一种解析模式:next()回调或async/await,不可混用) syncCurrentRoute参数清理 - 移除syncRoute()内部未使用的_from参数
[1.7.0] - 2026-06-25
新增
- 守卫重定向方式可控 -
next()回调新增可选options参数,支持在守卫重定向时指定导航方式NavigationGuardNextOptions-next()回调的可选参数类型,包含mode字段NavigationRedirectMode- 重定向方式类型('push' | 'replace' | 'relaunch')next(location, { mode })- 重定向时指定使用push/replace/relaunch方式- 未指定
mode时沿用触发守卫的原始导航方式(向后兼容) - 原始导航为
back时,未指定mode则回退为relaunch(因back无法跳转到页面栈外目标)
修复
- H5 平台
interceptUniApi导致 TabBar 点击卡死 - 1.6.3 通过调换执行顺序恢复了 switchTab 走守卫链,但 H5 平台下同步阻止uni.switchTab仍会导致 TabBar 组件内部「切换中」状态无法清除,后续点击被忽略。现对 H5 平台的 switchTab 改用「放行原始调用 + success 回调同步状态」策略- 新增
isWebPlatform()检测 H5 平台(通过window/document存在性判断) - 新增
handleWebSwitchTab()包装success回调,在 switchTab 完成后调用router.syncRoute()同步路由状态 - 权衡:H5 平台下外部
uni.switchTab调用不再经过前置守卫,TabBar 页面权限控制需在页面onShow生命周期中处理 - 小程序平台和 App 平台不受影响,仍走完整的「阻止 + 转发」流程
- 新增
[1.6.3] - 2026-06-24
修复
interceptUniApi导致 H5 端 TabBar 无法点击 - 拦截器invoke钩子中args.url = ''在handleInterceptedNavigation()之前执行,导致parseUniUrl('')返回空路径,switchTab导航被吞掉。H5 端 TabBar 是 Vue 组件,点击时调用uni.switchTab触发拦截器后 URL 被提前清空;小程序端 TabBar 是原生组件,点击不经过uni.switchTab,故不受影响。现已调换执行顺序,先解析 URL 并触发路由器导航,再清空 URL 作为双重保险,同时恢复switchTab走守卫链
[1.6.2] - 2026-06-23
修复
isReady()执行时机修正 -markReady()从setCurrentRoute()移到install()方法中,确保isReady()回调在所有插件(如 Pinia)安装完成后执行,而非在createRouter()构造时立即触发
[1.6.1] - 2026-06-23
优化
isSameQuery空对象快速路径 - 添加引用相等(a === b)和双空对象(keysA.length === 0)快速返回,避免高频调用场景下不必要的Object.keys和every开销Object.freeze逻辑集中化 - 将meta、query、params的冻结逻辑从setCurrentRoute和createStartLocation集中到createRouteLocation工厂函数中,消除重复代码,后续条件冻结只需改一处
[1.6.0] - 2026-06-23
新增
- 页面参数传递(params) -
push/replace/relaunch支持params参数,传递复杂数据(对象、数组等),不暴露在 URL 中,目标页面通过route.params读取RouteLocationPathRaw.params/RouteLocationNamedRaw.params- 导航时传入页面参数,支持 JSON 可序列化数据RouteLocation.params- 解析后的路由位置新增params字段(Readonly<ParamObject>),目标页面可直接读取ParamObject/ParamValue类型 - 页面参数类型定义,支持嵌套对象和数组QueryValue类型 - 查询参数值类型(string | number | boolean),用于query字段的输入类型
- 参数持久化存储 -
persistent选项将 params 持久化到uni.setStorageSync,H5 刷新后仍可读取RouteLocationPathRaw.persistent/RouteLocationNamedRaw.persistent- 单次导航指定是否持久化RouterOptions.paramsPersistent- 全局默认值,设为true时所有 params 默认持久化,单次导航可通过persistent覆盖
- 查询参数增强方法 -
RouteLocation提供三个便捷方法,自动解析 query 参数为指定类型queryInt(key, defaultValue?)- 将查询参数解析为整数,解析失败返回defaultValuequeryNumber(key, defaultValue?)- 将查询参数解析为数值(支持浮点),解析失败返回defaultValuequeryBool(key, defaultValue?)- 将查询参数解析为布尔值('true'/'1'→true,'false'/'0'→false),无法识别返回defaultValue
- RouterLink
paramsprop - 声明式导航支持传递页面参数,对应push的params选项 - RouterLink
persistentprop - 声明式导航支持参数持久化,对应push的persistent选项
[1.5.0] - 2026-06-18
新增
- 路由器就绪超时保护 -
readyTimeout配置项,防止路由器初始化异常时isReady()Promise 永久挂起RouterOptions.readyTimeout- 路由器就绪超时时间(毫秒),默认0(永不超时),设为大于 0 时超时后isReady()将 rejectrouter.isReady()超时 reject - 当配置了readyTimeout > 0且路由器在指定时间内未完成初始化时,await router.isReady()将抛出超时错误
修复
interceptUniApi拦截列表文档遗漏reLaunch- v1.0.0 文档仅列出navigateTo/redirectTo/switchTab/navigateBack四个 API,实际实现(含 v1.3.0 新增)拦截五个 API,已补充reLaunch到文档说明RouteMeta索引签名类型修正 -[key: string]类型从unknown修正为any,与实际实现保持一致router.back()返回值文档修正 - 返回值类型从Promise<void>修正为Promise<RouteLocation>,与实际实现保持一致
[1.4.0] - 2026-06-14
新增
- EventChannel 页面间通信 -
push支持events参数和eventChannel返回值,实现页面间双向通信RouteLocationPathRaw.events/RouteLocationNamedRaw.events- 导航时传入事件监听器,监听目标页面通过eventChannel.emit发送的事件NavigationResult.eventChannel-push返回结果新增eventChannel字段,用于向目标页面发送事件EventChannel接口 - 完整的on/once/off/emit方法定义EventListeners类型 - 事件监听器映射类型- 非 push 模式(replace / relaunch)传入
events时输出警告并忽略 - TabBar 页面(switchTab)不支持
events,传入时输出警告并忽略
- RouterLink
eventsprop - 声明式导航支持页面间通信,对应uni.navigateTo的events参数 - RouterLink
@navigated事件 - 导航成功后触发,参数为EventChannel | undefined,仅 push 模式返回eventChannel实例 - uni API 拦截器支持
events- 拦截uni.navigateTo时提取events参数转发到路由器 - 类型导出 - 新增
EventChannel和EventListeners类型导出
[1.3.0] - 2026-06-12
新增
- relaunch 导航方式 -
router.relaunch(location)关闭所有页面并打开目标页面,对应uni.reLaunch- TabBar 页面自动切换为
uni.switchTab uni.reLaunch不支持动画参数,传入时输出警告- 不进行重复导航检测(清栈场景下目标页面可能就是当前页面)
- 走完整守卫链(beforeEach → beforeEnter → beforeResolve → afterEach)
- TabBar 页面自动切换为
- RouterLink
relaunchprop - 声明式导航支持 relaunch 模式,优先级高于replace - uni API 拦截器新增
reLaunch- 拦截uni.reLaunch调用,转发到router.relaunch()
[1.2.0] - 2026-06-11
新增
- 导航动画 - 完整的页面切换动画支持,仅 App 端生效,其他平台自动忽略
NavigationAnimation接口 - 动画配置类型,包含type和可选duration字段UniAnimationType类型 - 覆盖 uni-app 支持的全部动画类型(slide-in/out、fade-in/out、zoom-in/out、pop-in/out、auto、none)DEFAULT_ANIMATION_DURATION常量 - 默认动画持续时间 300msRouteLocationPathRaw.animation/RouteLocationNamedRaw.animation- 导航时传入动画参数,覆盖meta.animationRouteMeta.animation- 路由级默认动画配置back(delta?, animation?)-back()方法新增可选animation参数RouterLink组件新增animationprop - 声明式导航支持动画- 动画优先级:
调用时传入>meta.animation>uni 默认值
[1.1.2] - 2026-06-10
修复
getCurrentPages()环境保护 - 新增safeGetCurrentPages()函数,在 SSR / Node 环境下getCurrentPages不存在时返回空数组,避免ReferenceError- 拦截器
invoke低版本基础库兼容 - 拦截外部导航调用时先将args.url置为空字符串,防止低版本小程序基础库忽略返回值false而继续执行原始 API - 拦截器重复安装警告 -
installInterceptors中检测到已有活跃管理器时输出console.warn,提醒只支持单路由器实例
[1.1.1] - 2026-06-09
修复
back()未触发afterEach守卫 -router.back()导航完成后未执行afterEach后置钩子,现已修复back()守卫模式错误 -back()导航的守卫模式从'push'修正为'back',确保守卫链正确识别返回导航syncRoute()忽略 query 变化 -syncRoute()仅比较路径未比较查询参数,导致 query 变化时路由状态不同步,现已同时比较 path 和 queryapp.onUnmount兼容性 -install中直接调用app.onUnmount在 uni-app 环境下报错(该 API 为 Vue 3.5+ 新增),已添加防御性检查
[1.1.0] - 2026-06-08
新增
- 守卫超时保护 -
guardTimeout配置项,守卫未在指定时间内调用next()时自动中止导航,默认 10000ms,设为 0 可禁用 - 路由变化监听 -
router.onRouteChange()注册路由状态变化监听器,导航完成和状态同步时触发,返回移除监听器的函数 - 路由状态同步标记 -
RouteLocation.synced字段,标识该路由变化是否由状态同步(如物理返回键)触发 - RouterLink 错误事件 -
<mxuni-router>组件新增@error事件,导航失败时触发并传入NavigationFailure对象
优化
- uni API 拦截增强 -
interceptUniApi拦截器逻辑优化,提升拦截稳定性 - 守卫执行增强 - 守卫链执行逻辑优化,支持超时保护与异常处理
- 组合式 API 增强 -
useRouter()/useRoute()内部实现优化 - fullPath 确定性 -
buildFullPath对 query 参数键排序,确保相同 query 生成一致的fullPath - install 类型修正 -
install(app)参数类型从unknown改为App,提供更好的类型提示
[1.0.0] - 2026-06-07
新增
- 路由器核心 -
createRouter()创建路由器实例,支持routes、strict、interceptUniApi配置项 - 路由导航 -
router.push()导航到新页面,router.replace()替换当前页面,router.back()返回上一页 - 命名路由 - 通过
name字段进行导航,无需硬编码路径字符串 - 路由元信息 -
meta字段支持title、isTab、requireAuth及自定义扩展字段 - 全局前置守卫 -
router.beforeEach()在每次导航前执行,支持中止、放行和重定向 - 全局解析守卫 -
router.beforeResolve()在所有前置守卫和路由独享守卫完成后执行 - 全局后置钩子 -
router.afterEach()在导航完成后执行 - 路由独享守卫 -
beforeEnter配置项,进入特定路由时触发 - 守卫重定向 - 守卫中调用
next(location)可重定向到其他路由,支持多级重定向(最大深度 10) - 组合式 API -
useRouter()获取路由器实例,useRoute()获取当前路由位置 - 错误处理 -
RouterError路由错误类,NavigationFailure导航失败类(包含to、from、cause信息) - 全局错误捕获 -
router.onError()注册错误处理回调 - 路由查询 -
router.resolve()解析路由位置(不执行导航),router.getRoutes()获取所有路由配置,router.hasRoute()检查路由是否存在 - TypeScript 类型提示 -
RouteNameMap接口支持模块增强,为路由名称和路径提供自动补全和类型检查 - uni API 拦截 -
interceptUniApi选项可拦截uni.navigateTo/uni.redirectTo/uni.switchTab/uni.navigateBack,统一走路由守卫流程 - 重复导航检测 -
push到当前页面时自动拒绝并抛出NAVIGATION_DUPLICATED错误 - 并发导航排队 - 多次并发导航自动排队,前一次完成后再执行下一次
- 路径自动规范化 - 路径自动补全前导
/,查询字符串自动解析为query对象
错误码
| 错误码 | 说明 |
|---|---|
NAVIGATION_ABORTED | 导航被守卫中止 |
NAVIGATION_CANCELLED | 导航被取消(守卫异常或重定向超限) |
NAVIGATION_DUPLICATED | 重复导航到当前位置 |
ROUTE_NOT_FOUND | 未找到匹配的路由 |
NAVIGATION_API_ERROR | uni 导航 API 调用失败 |
SETUP_ERROR | 路由器初始化或使用方式错误 |
[0.1.4] - 2025-07-28
- 新增 Hooks 函数
useMxRouter - 新增组件
Router - 类
Router中的push、back和go等函数在 app 平台支持动画 - 优化 md 文档描述
[0.1.3] - 2025-07-24
- 新增
umd.js文件 MxRouter类改名为Router类Router类内部支持单例模式调用Router类新增customGetCurrentRoute参数、setCustomGetCurrentRoute函数,设置自定义的getCurrentRoute函数
[0.1.1] - 2025-07-20
- 调整目录结构及 vite.config 配置,修改 md 文件内容与 npm 包对应
[0.1.0] - 2025-07-19
首个版本。
@mengxi/uni-router是一款为 uni-app 量身打造的路由库,提供与vue-router高度相似的路由风格,同时附带实用工具函数,助力开发者高效实现多平台路由管理。
- 类
vue-router风格 - 熟悉的 API 设计,降低学习成本,让vue-router用户快速上手 - 多导航方法 - 支持
push、replace、launch、tab、go、back等导航方式,满足不同场景跳转需求 - 全局守卫机制 - 前置守卫(权限验证、路由拦截)、后置钩子(日志记录、页面统计)
- 工具函数 - 提供
parseLocation、buildUrl、getCurrentRoute等工具,简化路由操作 - 多平台支持 - 适配 H5、小程序、App 等 uni-app 支持的平台
历史版本见 Releases。
