更新记录
1.0.0(2026-06-28) 下载此版本
首个稳定版本发布
平台兼容性
uni-app(4.61)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| - | √ | √ | √ | - | - | - | - | - |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| - | - | - | - | - | - | - | - | - | - | - | - |
# jz-page-transition
一款专为 uni-app H5 端打造的 路由过渡动画 + 边缘手势返回 + 离开守卫 一站式解决方案。
📖 目录
- 介绍
- 功能特性
- 安装
- 快速开始
- 完整配置项
- 支持的动画类型
- 页面级配置(4 种方式)
- 手势返回模块
- 离开守卫(脏数据二次确认)
- API 参考
- TransitionView 组件
- 自定义动画类
- 常见场景示例
- 注意事项 & FAQ
- 目录结构
- 更新日志
- 许可证
介绍
jz-page-transition 解决了 uni-app 编译到 H5 端时路由切换无过渡动画 的痛点,并补齐了 App 端原生具备但 H5 端缺失的能力:
- 🎬 多种过渡动画 —— slide / fade / zoom / pop / flip / cube …
- 👆 iOS 风格边缘手势返回 —— 跟手 + 接力,体验等同原生
- 🛡️ 统一离开守卫中心 —— 一次注册,同时覆盖
导航栏返回/uni.navigateBack/浏览器后退/边缘手势 - ⚡ 零侵入 —— 自动拦截
uni.navigateTo等 API,无需改造业务代码
仅在 H5 平台生效,其他平台自动绕过,不影响 App / 小程序的原生行为。
功能特性
| 模块 | 特性 |
|---|---|
| 路由过渡 | ✅ 10 种内置动画类型,支持自定义类扩展 |
| 路由过渡 | ✅ 自动拦截 5 个 uni 路由 API(navigateTo / navigateBack / redirectTo / reLaunch / switchTab) |
| 路由过渡 | ✅ 三级优先级(调用时参数 > 页面配置 > 全局默认) |
| 路由过渡 | ✅ 自动读取 pages.json 中的 animationType / animationDuration |
| 路由过渡 | ✅ 调用时动态传入 animationType 与 animationDuration |
| 路由过渡 | ✅ GPU 加速、will-change 优化、抑制系统横向手势 |
| 手势返回 | ✅ 左 / 右 / 双侧边缘起手,可配置触发距离与速度 |
| 手势返回 | ✅ 实时跟手动画 + 接力动画,松手即完成 |
| 手势返回 | ✅ 页面白/黑名单(includes / excludes) |
| 离开守卫 | ✅ 全局守卫 / 页面级守卫 / 脏数据检查器 |
| 离开守卫 | ✅ 一次注册覆盖:导航栏返回 / API 返回 / 浏览器后退 / 边缘手势 |
| 离开守卫 | ✅ 内置确认弹窗,支持自定义 render |
| 工程化 | ✅ 纯 JS + JSDoc,Vue 2 / Vue 3 双支持,可被 TS 项目无障碍引用 |
安装
1. 拷贝插件
将插件目录放入项目的 src/uni_modules 下:
src/uni_modules/jz-page-transition/
来源于 uni_modules 插件市场时,HBuilderX 会自动放置到正确位置。
2. 引入插件
main.ts / main.js:
import { createSSRApp } from 'vue'
import App from './App.vue'
// @ts-ignore
import jzTransition from '@/uni_modules/jz-page-transition'
export function createApp() {
const app = createSSRApp(App)
app.use(jzTransition) // 使用默认配置即可工作
return { app }
}
插件已内置
#ifdef H5条件编译,App / 小程序端app.use调用不会有任何副作用,可放心放在公共入口。
快速开始
最小配置(开箱即用)
app.use(jzTransition)
推荐配置(含手势返回)
app.use(jzTransition, {
enable: true,
defaultType: 'slide-horizontal',
duration: 300,
timingFunction: 'ease-out',
gestureBack: {
enable: true,
direction: 'left', // iOS 风格,从左边缘起手向右滑返回
confirm: { enable: true } // 配合脏数据守卫弹出二次确认
}
})
完整配置项
全局选项
| 字段 | 类型 | 默认 | 说明 |
|---|---|---|---|
enable |
boolean |
true |
总开关,关闭后所有路由走原生 |
defaultType |
TransitionType |
'slide-horizontal' |
默认动画类型,见动画列表 |
duration |
number |
300 |
动画时长(毫秒),建议 200~400 |
timingFunction |
string |
'ease-out' |
CSS 缓动函数 |
usePagesJson |
boolean |
true |
是否读取 pages.json 的 style.app-plus.animationType |
pageConfig |
object |
{} |
页面级配置,优先级高于 pages.json |
gestureBack |
object |
undefined |
手势返回子模块配置(不传则不启用) |
pageConfig 写法
pageConfig: {
// 简写:仅指定动画类型
'/pages/index/index': 'fade',
// 详细:可单独配置时长、缓动、是否启用
'/pages/detail/detail': {
type: 'zoom-fade',
duration: 400,
timingFunction: 'ease-in',
enable: true
}
}
gestureBack 选项
| 字段 | 类型 | 默认 | 说明 |
|---|---|---|---|
enable |
boolean |
false |
是否启用手势返回 |
direction |
'left' \| 'right' \| 'both' \| 'none' |
'left' |
起手所在的屏幕边缘 |
edgeWidth |
number |
30 |
边缘触发宽度(px) |
threshold |
number |
0.3 |
触发返回的距离阈值(占屏宽比例) |
velocity |
number |
0.3 |
触发返回的速度阈值(px/ms) |
followFinger |
boolean |
true |
是否启用跟手动画 |
includes |
string[] |
[] |
白名单:仅这些路径启用 |
excludes |
string[] |
[] |
黑名单:这些路径禁用 |
confirm |
object |
见下表 | 二次确认弹窗配置 |
onBack |
(ctx) => void |
null |
成功返回时回调 |
onCancel |
(ctx) => void |
null |
用户取消时回调 |
gestureBack.confirm 选项
| 字段 | 类型 | 默认 | 说明 |
|---|---|---|---|
enable |
boolean |
false |
是否启用二次确认弹窗 |
title |
string |
'提示' |
弹窗标题 |
content |
string |
'当前内容未保存,确认离开吗?' |
弹窗内容 |
confirmText |
string |
'离开' |
确认按钮文案 |
cancelText |
string |
'继续编辑' |
取消按钮文案 |
confirmColor |
string |
'#e64340' |
确认按钮颜色 |
render |
Function \| null |
null |
自定义渲染:(opts) => Promise<boolean> |
支持的动画类型
| 类型 | 效果说明 | 适用场景 |
|---|---|---|
slide-horizontal |
水平滑动(默认,iOS 风格) | 列表 → 详情 |
slide-vertical |
垂直滑动 | 从底部弹出页面 |
fade |
淡入淡出 | 同级页切换、Tab |
zoom |
缩放 | 弹窗、图片预览 |
zoom-fade |
缩放 + 淡入淡出 | 卡片切换 |
pop |
弹出(带弹性) | 模态框 |
flip-horizontal |
水平 3D 翻转 | 特殊创意 |
flip-vertical |
垂直 3D 翻转 | 特殊创意 |
cube |
立方体旋转 | 营销页 |
none |
无动画 | 禁用 |
App 端 animationType 自动映射
为兼容业务代码中已有的 App 端写法,插件会自动把 animationType 映射到内部类型:
App 端 animationType |
内部类型 |
|---|---|
pop-in / slide-in-right |
slide-horizontal |
slide-in-bottom |
slide-vertical |
slide-in-left |
slide-horizontal-reverse |
fade-in / fade-out |
fade |
zoom-in / zoom-out |
zoom |
zoom-fade-in / zoom-fade-out |
zoom-fade |
pop-out |
pop |
flip-in / cube-in |
flip-horizontal / cube |
none |
none |
页面级配置(4 种方式)
优先级(高 → 低): 调用时参数 >
pageConfig>pages.json> 全局默认
方式一:pageConfig 全局指定
app.use(jzTransition, {
pageConfig: {
'/pages/detail/detail': { type: 'fade', duration: 200 },
'/pages/login/login': 'pop'
}
})
方式二:pages.json 配置(无侵入,推荐)
{
"path": "pages/detail/detail",
"style": {
"app-plus": {
"animationType": "fade-in",
"animationDuration": 250
}
}
}
方式三:调用时动态传参(最灵活)
uni.navigateTo({
url: '/pages/detail/detail',
animationType: 'fade-in', // 兼容 App 写法
animationDuration: 250
})
uni.navigateBack({
delta: 1,
animationType: 'fade',
animationDuration: 200
})
uni.redirectTo({
url: '/pages/login/login',
animationType: 'pop',
animationDuration: 250
})
自定义参数(
animationType/animationDuration)会被插件自动剥离,不会触发 uni 的参数校验错误。
方式四:页面内使用 <TransitionView> 组件
<template>
<transition-view type="fade" :duration="200">
<!-- 页面内容 -->
</transition-view>
</template>
手势返回模块
启用
app.use(jzTransition, {
gestureBack: {
enable: true,
direction: 'left', // iOS 风格
edgeWidth: 30,
threshold: 0.3,
velocity: 0.3
}
})
仅在部分页面启用
gestureBack: {
enable: true,
includes: ['/pages/detail/detail', '/pages/order/order']
}
排除某些页面
gestureBack: {
enable: true,
excludes: ['/pages/login/login']
}
在页面中订阅手势返回事件
任意 .js / .vue 中(无需 setup 上下文):
import { gestureBack } from '@/uni_modules/jz-page-transition'
const off = gestureBack.addGuard((ctx) => {
// ctx: { from, direction, key }
console.log('手势触发返回', ctx)
return true // true=放行;false=拦截;object=弹窗配置
})
// 页面卸载时取消订阅
onUnmounted(off)
Vue 3 <script setup> 推荐写法:
import { useGestureBack } from '@/uni_modules/jz-page-transition'
const gb = useGestureBack()
const off = gb.on('order-edit', (ctx) => {
if (!dirty.value) return true
return { content: '订单尚未保存,确认离开吗?' }
})
onUnmounted(off)
离开守卫(脏数据二次确认)
registerDirty() 是本插件最有特色的能力 —— 一次注册,覆盖所有返回入口:
- ✅ 顶部导航栏返回按钮
- ✅ 业务代码调用
uni.navigateBack() - ✅ 浏览器后退 / 物理返回键 /
popstate - ✅ 边缘手势返回
基础用法
import { gestureBack } from '@/uni_modules/jz-page-transition'
import { ref, onUnmounted } from 'vue'
const dirty = ref(false)
const off = gestureBack.registerDirty(
'order-edit', // 页面 key(可选)
() => dirty.value, // 脏数据检查器,返回 true 时拦截
{ // 弹窗文案覆盖(可选)
title: '提示',
content: '订单尚未保存,确认离开吗?',
confirmText: '离开',
cancelText: '继续编辑'
}
)
onUnmounted(off)
简化签名(不需要 key)
gestureBack.registerDirty(() => dirty.value)
gestureBack.registerDirty(() => dirty.value, { content: '确认离开?' })
自定义确认 UI
app.use(jzTransition, {
gestureBack: {
enable: true,
confirm: {
enable: true,
render(options) {
// 返回 Promise<boolean>,true 表示放行
return new Promise((resolve) => {
myCustomModal.show({
...options,
onConfirm: () => resolve(true),
onCancel: () => resolve(false)
})
})
}
}
}
})
API 参考
app.config.globalProperties.$transition
// 设置全局配置
this.$transition.setDefaultConfig({ enable: false })
// 获取当前配置
this.$transition.getConfig()
// 获取动画实例
this.$transition.getTransition('fade', { duration: 250 })
// 获取页面配置
this.$transition.getPageConfig('/pages/detail/detail')
// 注册自定义动画
this.$transition.registerTransition('my-anim', MyTransitionClass)
// 取消自定义动画
this.$transition.unregisterTransition('my-anim')
// 查询支持的所有动画类型
this.$transition.getSupportedTypes()
// 获取页面栈快照
this.$transition.getPageStack()
gestureBack 代理对象(推荐)
任何文件、任何时机调用都安全,内部用 Proxy 取最新单例:
import { gestureBack } from '@/uni_modules/jz-page-transition'
gestureBack.addGuard(guard) // 全局守卫
gestureBack.on(key, handler) // 页面级守卫
gestureBack.registerDirty(key?, checker, confirm?) // 脏数据检查
gestureBack.setConfig(partial) // 动态修改配置
gestureBack.getConfig() // 获取当前配置
gestureBack.enable() // 启用
gestureBack.disable() // 禁用
Composition API
import { useGestureBack, getGestureBack } from '@/uni_modules/jz-page-transition'
// 在 setup 中
const gb = useGestureBack() // 优先 inject,兜底单例
// 在普通 js 中
const gb = getGestureBack() // 取全局单例
TransitionView 组件
需要更细粒度地控制某个区域的过渡时使用:
<template>
<transition-view
:enable="true"
type="fade"
:duration="300"
timing-function="ease-out"
@before-enter="onBeforeEnter"
@after-enter="onAfterEnter"
>
<!-- 内容 -->
</transition-view>
</template>
| Prop | 类型 | 默认 | 说明 |
|---|---|---|---|
enable |
Boolean |
true |
是否启用 |
type |
String |
'' |
动画类型,留空时跟随全局 |
duration |
Number |
300 |
动画时长 |
timingFunction |
String |
'ease-out' |
缓动函数 |
自定义动画类
继承 BaseTransition 即可:
import { BaseTransition } from '@/uni_modules/jz-page-transition'
class MyTransition extends BaseTransition {
beforeEnter(el) {
el.style.opacity = '0'
el.style.transform = 'translateY(100%)'
}
enter(el, done) {
el.style.transition = `all ${this.duration}ms ${this.timingFunction}`
el.style.opacity = '1'
el.style.transform = 'translateY(0)'
setTimeout(done, this.duration)
}
afterEnter(el) {
el.style.transition = ''
}
beforeLeave(el) { /* ... */ }
leave(el, done) { /* ... */ }
afterLeave(el) { /* ... */ }
}
// 注册
this.$transition.registerTransition('my-anim', MyTransition)
// 使用
uni.navigateTo({ url: '/pages/x/x', animationType: 'my-anim' })
常见场景示例
1. 详情页用 fade,其他页用默认
app.use(jzTransition, {
pageConfig: { '/pages/detail/detail': 'fade' }
})
2. 关闭某个页面的动画
app.use(jzTransition, {
pageConfig: {
'/pages/loading/loading': { enable: false }
}
})
3. 表单页防误返回
// pages/order-edit.vue
import { gestureBack } from '@/uni_modules/jz-page-transition'
const dirty = ref(false)
onMounted(() => {
const off = gestureBack.registerDirty(() => dirty.value)
onUnmounted(off)
})
4. 调用时临时变更动画
uni.navigateTo({
url: '/pages/preview/preview',
animationType: 'zoom-fade',
animationDuration: 400
})
5. 运行时切换全局动画
// 弱网下关闭动画提速
if (slowNetwork) {
this.$transition.setDefaultConfig({ enable: false })
}
注意事项 & FAQ
Q1:插件在 App / 小程序端会生效吗?
不会。 插件入口已用 #ifdef H5 条件编译包裹,App / 小程序端的 app.use 调用会被视为 no-op,不影响原生动画体验。
Q2:手势返回和 iOS Safari 自带的边缘返回冲突?
插件已在全局注入 overscroll-behavior-x: contain + touch-action: pan-y,抑制了系统横向手势,整屏由 TouchTracker 接管。
Q3:tabBar 页面有动画吗?
switchTab 默认使用 fade,业务代码可通过传入 animationType 自定义;如果完全不需要,使用 'none'。
Q4:浏览器后退按钮会触发 registerDirty 吗?
会。 leave-guard 中心同时接管了 uni.navigateBack 和 popstate,注册一次即可覆盖所有返回入口。
Q5:动画期间能否再次触发返回?
插件内部用 isAnimating 标记防止重复触发,动画期间的 navigateBack 会直接走原生方法以避免死锁。
Q6:如何完全卸载/暂停插件?
this.$transition.setDefaultConfig({ enable: false }) // 暂停过渡
gestureBack.disable() // 暂停手势
this.$transition.restoreRouter() // 还原 uni 路由 API
Q7:性能优化建议
- 动画时长建议 200~300ms
- 长列表页慎用
cube/flip等 3D 动画 - 在
<TransitionView>内部尽量避免高频 reactive 重渲染
目录结构
src/uni_modules/jz-page-transition/
├── package.json
├── readme.md
├── changelog.md
├── index.js # 插件入口(install 函数)
├── components/
│ └── transition-view/
│ └── transition-view.vue # 过渡动画容器组件
├── core/
│ ├── base-transition.js # 动画基类
│ ├── transition-manager.js # 动画管理器 / 路由拦截
│ └── pages-json-reader.js # pages.json 读取器
├── transitions/
│ ├── slide-transition.js
│ ├── fade-transition.js
│ ├── zoom-transition.js
│ ├── zoom-fade-transition.js
│ ├── pop-transition.js
│ ├── flip-transition.js
│ ├── cube-transition.js
│ └── none-transition.js
├── utils/
│ ├── dom.js # DOM 操作工具
│ ├── animation.js # 动画工具函数
│ └── platform.js # 平台检测
├── config/
│ ├── default.js # 默认配置
│ └── constants.js # 常量定义
└── js_sdk/
├── gesture-back/ # 手势返回模块
│ ├── index.js
│ ├── manager.js # GestureBackManager
│ ├── touch-tracker.js # 触摸跟踪器
│ ├── back-resolver.js # 守卫链调度
│ ├── confirm-dialog.js # 确认弹窗
│ └── constants.js
└── router-guard/
└── leave-guard.js # 离开守卫中心(统一入口)
更新日志
详见 changelog.md。
许可证
MIT © jz-team

收藏人数:
下载插件并导入HBuilderX
下载插件ZIP
赞赏(0)
下载 2449
赞赏 0
下载 12348431
赞赏 1925
赞赏
京公网安备:11010802035340号