
Skyline Route
- 677 installs
- 48 repo stars
- Updated June 3, 2026
- wechat-miniprogram/skyline-skills
skyline-route is a Claude Code skill that implements custom page transitions, half-screen popups, card expansions, and gesture-driven navigation in WeChat Mini Programs using the Skyline rendering engine for developers b
About
skyline-route is a skill from wechat-miniprogram/skyline-skills covering Skyline custom routing and page transitions in WeChat Mini Programs. It documents three capability layers: 7 preset wx:// route types for one-line common transitions, custom routeBuilder controllers for fully controlled enter/exit animations, and open-container element transitions for card-to-detail expansions. The skill also covers Router API usage, primaryAnimation and secondaryAnimation controllers, and configurable back gestures (horizontal, vertical, multi-direction). Developers use skyline-route when implementing half-screen modals, bottom sheets, scale fades, and gesture-driven page returns on Skyline.
- Supports 7 preset wx:// routes for instant common transitions
- Full control via routeBuilder for completely custom animations
- Implements card-expand and open-container element-level transitions
- Configurable multi-direction pop gestures with userGestureInProgress tracking
- Router API plus navigateTo parameter and route event listeners
Skyline Route by the numbers
- 677 all-time installs (skills.sh)
- +29 installs in the week ending Jul 27, 2026 (Skillselion tracking)
- Ranked #511 of 2,245 Frontend Development skills by installs in the Skillselion catalog
- Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/wechat-miniprogram/skyline-skills --skill skyline-routeAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 677 |
|---|---|
| repo stars | ★ 48 |
| Last updated | June 3, 2026 |
| Repository | wechat-miniprogram/skyline-skills ↗ |
How do you add custom page transitions in WeChat Skyline?
Implement custom page transitions, half-screen popups, card-to-detail expansions, and gesture-driven navigation inside WeChat Mini Programs using the Skyline rendering
Who is it for?
WeChat Mini Program developers implementing Skyline custom routing, half-screen modals, and gesture-driven page transitions.
Skip if: Standard WebView mini programs without Skyline rendering or backends unrelated to WeChat client navigation.
When should I use this skill?
A developer mentions custom-route, routeBuilder, navigateTo transitions, half-screen popups, or open-container in a Skyline mini program.
What you get
Configured Skyline routeBuilder handlers, preset or custom wx:// transitions, open-container animations, and Router API navigation flows.
- routeBuilder configuration
- Preset or custom wx:// transition setup
- open-container transition markup
By the numbers
- Documents 7 preset wx:// Skyline route transition types
- Covers 3 routing capability layers: preset, custom routeBuilder, open-container
Files
Skyline 自定义路由与页面转场
适用场景
- 实现自定义页面转场动画(半屏、缩放、渐显等)
- 使用预设路由快速实现常见转场效果
- 配置页面返回手势(横向/纵向/多方向)
- 实现卡片展开到详情页的容器转场动画
- 通过 Router API 管理自定义路由
核心概念
路由能力层级
| 层级 | 能力 | 适用场景 |
|---|---|---|
| 预设路由 | 一行代码使用 7 种内置效果 | 快速实现常见转场 |
| 自定义路由 | 通过 routeBuilder 完全控制动画 | 高度定制化转场 |
| 容器转场 | <open-container> 元素级过渡 | 卡片展开到详情页 |
动画控制器
| 属性 | 说明 |
|---|---|
| primaryAnimation | 页面进入/退出动画进度(0→1 进入,1→0 退出) |
| secondaryAnimation | 下一页进入时当前页动画进度(与下一页 primaryAnimation 同步) |
| userGestureInProgress | 当前路由进度是否由手势控制 |
| startUserGesture / stopUserGesture | 手势接管/释放路由控制 |
| didPop | 确认返回上一页 |
文档索引
根据需求快速定位(路径相对于 references/):
| 我想要... | 查阅文档 |
|---|---|
| 了解自定义路由原理和接口 | custom-route/custom-route-guide.md |
| 查看半屏/手势返回代码模式 | custom-route/route-patterns.md |
| 快速使用预设路由 | preset-route/preset-route.md |
| 配置页面返回手势 | pop-gesture/pop-gesture.md |
| 实现卡片展开转场 | open-container/open-container.md |
| 查看 Router API | api/router-api.md |
| 了解 navigateTo 路由参数 | api/navigate-to.md |
| 监听路由事件 | api/route-events.md |
强制规则
MUST(必须遵守)
1. 自定义路由仅在连续 Skyline 页面间生效:WebView 页面不支持自定义路由
// ✅ A 页(Skyline) → B 页(Skyline):自定义路由生效
// ❌ A 页(WebView) → B 页(Skyline):降级为默认路由2. 动画处理函数必须声明 'worklet' 指令:
// ✅ 正确
const handlePrimaryAnimation = () => {
'worklet'
return { transform: `translateX(${...}px)` }
}
// ❌ 错误:缺少 worklet 指令,无法在 UI 线程执行
const handlePrimaryAnimation = () => {
return { transform: `translateX(${...}px)` }
}3. 手势接管必须成对调用 startUserGesture / stopUserGesture:
// ✅ 正确
handleDragStart() {
'worklet'
this.customRouteContext.startUserGesture()
}
handleDragEnd() {
'worklet'
// ... 动画完成回调中:
stopUserGesture()
}4. 确认返回时必须调用 didPop:引擎无法自动判断开发者是否要退出页面
// ✅ 正确:动画完成后调用 didPop
primaryAnimation.value = timing(0.0, { duration }, () => {
'worklet'
didPop()
stopUserGesture()
})NEVER(禁止行为)
1. NEVER 在手势处理中忘记调用 startUserGesture 就直接修改 primaryAnimation.value 2. NEVER 假设自定义路由在 WebView 页面生效(低版本基础库会降级) 3. NEVER 在非 worklet 函数中访问 primaryAnimation.value
Quick Reference
预设路由速查
| routeType | 效果 | 最低基础库 |
|---|---|---|
wx://bottom-sheet | 底部弹出半屏 | 3.1.0 |
wx://upwards | 自底向上全屏 | 3.1.0 |
wx://zoom | 缩放进入 | 3.1.0 |
wx://cupertino-modal | iOS 风格模态 | 3.1.0 |
wx://cupertino-modal-inside | iOS 模态内嵌 | 3.1.0 |
wx://modal-navigation | 模态导航 | 3.1.0 |
wx://modal | 模态弹窗 | 3.1.0 |
// 使用预设路由
wx.navigateTo({
url: 'xxx',
routeType: 'wx://bottom-sheet',
routeOptions: { height: 60, round: true }
})API 速查
| API | 说明 | 最低基础库 |
|---|---|---|
wx.router.addRouteBuilder(type, builder) | 注册自定义路由 | 2.29.2 |
wx.router.removeRouteBuilder(type) | 移除自定义路由 | 2.29.2 |
wx.router.getRouteContext(this) | 获取路由上下文 | 2.29.2 |
wx.navigateTo({ routeType }) | 指定路由类型跳转 | 2.29.2 |
wx.navigateTo({ routeConfig }) | 覆盖路由配置 | 3.4.0 |
wx.navigateTo({ routeOptions }) | 传入路由参数 | 3.4.0 |
wx.navigateTo({ withOpenContainer }) | 容器转场跳转 | 3.12.2 |
wx.onBeforeAppRoute(fn) | 路由执行前监听 | 3.5.5 |
wx.onAppRoute(fn) | 路由执行后监听 | 3.5.5 |
自定义路由最小示例
// 注册:从右滑入
wx.router.addRouteBuilder('slide', ({ primaryAnimation }) => {
const { windowWidth } = wx.getWindowInfo()
const handlePrimaryAnimation = () => {
'worklet'
const transX = windowWidth * (1 - primaryAnimation.value)
return { transform: `translateX(${transX}px)` }
}
return { handlePrimaryAnimation }
})
// 跳转
wx.navigateTo({ url: 'pageB', routeType: 'slide' })场景决策表
| 场景 | 推荐方案 |
|---|---|
| 底部弹出半屏 | 预设路由 wx://bottom-sheet |
| iOS 风格模态 | 预设路由 wx://cupertino-modal |
| 自定义半屏 + 手势 | 自定义路由 + handlePrimaryAnimation |
| 卡片展开到详情页 | <open-container> 容器转场 |
| 页面渐显效果 | 自定义路由 + opacity 动画 |
| 需要纵向返回手势 | popGestureDirection: 'vertical' |
相关技能
| 场景 | 推荐技能 | 说明 |
|---|---|---|
| 动画开发 | skyline-worklet | Worklet 动画系统(timing/spring/Easing) |
| 手势处理 | skyline-components | gesture-handler 手势组件 |
| 共享元素 | skyline-components | share-element 页面间动画 |
| 配置详解 | skyline-config | app.json/page.json 配置 |
| 概览迁移 | skyline-overview | Skyline 概览与迁移指南 |
References 目录结构
references/
├── api/
│ ├── navigate-to.md
│ ├── route-events.md
│ └── router-api.md
├── custom-route/
│ ├── custom-route-guide.md
│ └── route-patterns.md
├── open-container/
│ └── open-container.md
├── pop-gesture/
│ └── pop-gesture.md
└── preset-route/
└── preset-route.mdwx.navigateTo 路由参数
概述
wx.navigateTo 保留当前页面,跳转到应用内的某个页面。基础库 2.29.2 起支持自定义路由相关参数。
路由相关参数
| 属性 | 类型 | 必填 | 说明 | 最低基础库 |
|---|---|---|---|---|
| url | string | 是 | 跳转页面路径(非 tabBar),路径后可带参数 | 1.0.0 |
| routeType | string | 否 | 自定义路由类型(通过 addRouteBuilder 注册的名称或 wx:// 预设类型) | 2.29.2 |
| routeConfig | Object | 否 | 自定义路由配置,覆盖 routeBuilder 返回的配置 | 3.4.0 |
| routeOptions | Object | 否 | 自定义路由参数,作为 routeBuilder 的第二个参数 | 3.4.0 |
| withOpenContainer | Object | 否 | Skyline 下指定路由动画所用 OpenContainer 实例 | 3.12.2 |
| events | Object | 否 | 页面间通信接口 | 2.7.3 |
| success | function | 否 | 成功回调,参数含 eventChannel | - |
| fail | function | 否 | 失败回调 | - |
| complete | function | 否 | 完成回调 | - |
使用自定义路由
// 1. 使用已注册的自定义路由
wx.navigateTo({
url: 'pageB',
routeType: 'myCustomRoute'
})
// 2. 使用预设路由
wx.navigateTo({
url: 'pageB',
routeType: 'wx://bottom-sheet'
})routeConfig 覆盖配置
routeConfig 接受 CustomRouteConfig 的所有字段,传入的值会覆盖 routeBuilder 返回的配置:
wx.navigateTo({
url: 'pageB',
routeType: 'wx://bottom-sheet',
routeConfig: {
popGestureDirection: 'vertical',
fullscreenDrag: true,
transitionDuration: 500,
barrierDismissible: true,
barrierColor: 'rgba(0,0,0,0.5)',
}
})routeOptions 动态参数
routeOptions 作为 routeBuilder 函数的第二个参数传入:
// 跳转时传入参数
wx.navigateTo({
url: 'pageB',
routeType: 'wx://bottom-sheet',
routeOptions: {
height: 80,
round: false,
}
})
// routeBuilder 中接收
const myRouteBuilder = (routeContext, routeOptions) => {
const height = routeOptions.height || 60
// ...使用 height 控制动画
}withOpenContainer 容器转场
Skyline 渲染引擎下,通过 withOpenContainer 指定容器转场动画的 OpenContainer 实例:
Page({
goDetail() {
this.createSelectorQuery()
.select('.my-container')
.node()
.exec(res => {
wx.navigateTo({
url: 'detailPage',
withOpenContainer: res[0].node,
})
})
}
})页面间通信(EventChannel)
// 发起页
wx.navigateTo({
url: 'test?id=1',
events: {
acceptDataFromOpenedPage(data) {
console.log(data)
},
},
success(res) {
res.eventChannel.emit('acceptDataFromOpenerPage', { data: 'test' })
}
})
// 被打开页面(test.js)
Page({
onLoad(option) {
const eventChannel = this.getOpenerEventChannel()
eventChannel.emit('acceptDataFromOpenedPage', { data: 'test' })
eventChannel.on('acceptDataFromOpenerPage', function(data) {
console.log(data)
})
}
})重要约束
- 不能跳转到 tabBar 页面
- 页面栈最多十层(连续 Skyline 页面不受此限制)
- 低版本基础库会降级到默认路由动画,不会报错
- 插件页面与宿主页面之间不能互相调用
路由事件监听 API
概述
基础库 3.5.5 起提供全局路由事件监听接口,可在路由执行前后获取路由信息。
wx.onBeforeAppRoute(function listener)
监听路由事件下发后、执行路由逻辑前的事件。
最低基础库:3.5.5
listener 回调参数(Object res)
| 属性 | 类型 | 说明 |
|---|---|---|
| path | string | 页面路径 |
| query | Object | 路由参数 |
| renderer | string | 渲染引擎(webview / skyline / xr-frame) |
| openType | string | 路由打开类型 |
| webviewId | number | 当前页面 id |
| routeEventId | string | 路由事件 id |
| pipMode | string | 画中画模式(min 缩小为小窗 / max 还原为页面) |
| notFound | boolean | 是否未找到页面 |
| page | Object | 当前打开页面的相关配置 |
代码示例
const func = function (res) {
console.log('路由即将执行:', res.path)
console.log('渲染引擎:', res.renderer) // 'skyline' 或 'webview'
console.log('路由类型:', res.openType)
}
wx.onBeforeAppRoute(func)
// 取消监听
wx.offBeforeAppRoute(func)wx.onAppRoute(function listener)
监听路由事件下发后、执行路由逻辑后的事件。
最低基础库:3.5.5
listener 回调参数(Object res)
与 wx.onBeforeAppRoute 相同,但额外包含:
| 属性 | 类型 | 说明 |
|---|---|---|
| timeStamp | number | 路由下发的时间戳(onAppRoute 独有) |
其余字段(path、query、renderer、openType、webviewId、routeEventId、pipMode、notFound、page)与 onBeforeAppRoute 一致。
代码示例
const func = function (res) {
console.log('路由已执行:', res.path)
console.log('时间戳:', res.timeStamp)
}
wx.onAppRoute(func)
// 取消监听
wx.offAppRoute(func)两者区别
| 接口 | 触发时机 | 独有字段 |
|---|---|---|
wx.onBeforeAppRoute | 路由逻辑执行前 | 无 |
wx.onAppRoute | 路由逻辑执行后 | timeStamp |
renderer 字段值
| 值 | 说明 |
|---|---|
webview | WebView 渲染引擎 |
skyline | Skyline 渲染引擎 |
xr-frame | xr-frame 解决方案 |
可用于判断目标页面的渲染引擎类型:
wx.onBeforeAppRoute(function(res) {
if (res.renderer === 'skyline') {
// Skyline 页面,可预加载资源
wx.preloadSkylineView()
}
})重要说明
- 在低于 3.5.5 版本的基础库中也可能存在此接口,但参数可能与当前文档不同
- 支持小程序插件(基础库 >= 3.5.5)
- 支持微信鸿蒙 OS 版
取消监听
| 监听 | 取消 |
|---|---|
wx.onBeforeAppRoute(fn) | wx.offBeforeAppRoute(fn) |
wx.onAppRoute(fn) | wx.offAppRoute(fn) |
注意:取消监听时必须传入与监听时相同的函数引用。
wx.router API 参考
概述
wx.router 是 Skyline 自定义路由系统的核心 API 对象,提供路由动画的注册、移除和上下文获取功能。
最低基础库版本:2.29.2
限制:所有 wx.router 方法均不支持小程序插件。
router.addRouteBuilder(routeType, routeBuilder)
添加自定义路由配置,将路由类型名称与路由动画定义函数绑定。
参数
| 参数 | 类型 | 说明 |
|---|---|---|
| routeType | string | 路由类型标识(自定义名称) |
| routeBuilder | CustomRouteBuilder | 路由动画定义函数 |
CustomRouteBuilder 签名
type CustomRouteBuilder = (
routeContext: CustomRouteContext,
routeOptions: Record<string, any>
) => CustomRouteConfigrouteContext:包含primaryAnimation、secondaryAnimation等动画控制器routeOptions:通过wx.navigateTo({ routeOptions })传入的参数(基础库 3.4.0+)
代码示例
// 定义自定义路由:从右侧推入
const slideRouteBuilder = (customRouteContext) => {
const { primaryAnimation } = customRouteContext
const { windowWidth } = wx.getWindowInfo()
const handlePrimaryAnimation = () => {
'worklet'
const transX = windowWidth * (1 - primaryAnimation.value)
return {
transform: `translateX(${transX}px)`,
}
}
return { handlePrimaryAnimation }
}
// 注册
wx.router.addRouteBuilder('slide', slideRouteBuilder)
// 使用
wx.navigateTo({
url: 'xxx',
routeType: 'slide'
})关键约束
handlePrimaryAnimation/handleSecondaryAnimation/handlePreviousPageAnimation必须使用'worklet'指令routeBuilder返回的配置项可被wx.navigateTo({ routeConfig })覆盖(基础库 3.4.0+)
router.removeRouteBuilder(routeType)
移除已注册的自定义路由配置。
参数
| 参数 | 类型 | 说明 |
|---|---|---|
| routeType | string | 之前注册的路由类型标识 |
代码示例
wx.router.removeRouteBuilder('slide')router.getRouteContext(this)
获取页面对应的自定义路由上下文对象。
参数
| 参数 | 类型 | 说明 |
|---|---|---|
| this | Object | 页面或自定义组件实例 |
返回值
返回 CustomRouteContext 对象,包含以下属性:
| 属性 | 类型 | 说明 |
|---|---|---|
| primaryAnimation | SharedValue\<number\> | 页面进入/退出动画进度 |
| primaryAnimationStatus | SharedValue\<number\> | primaryAnimation 状态 |
| secondaryAnimation | SharedValue\<number\> | 页面被压入/恢复时的动画进度 |
| secondaryAnimationStatus | SharedValue\<number\> | secondaryAnimation 状态 |
| userGestureInProgress | SharedValue\<number\> | 手势是否正在控制路由 |
| startUserGesture | function | 开始手势接管路由 |
| stopUserGesture | function | 结束手势接管路由 |
| didPop | function | 确认返回上一页 |
| routeType | string | 当前路由类型 |
代码示例
Page({
onLoad() {
this.customRouteContext = wx.router.getRouteContext(this)
// 可在 worklet 手势处理中使用
},
handleGesture(e) {
'worklet'
const { primaryAnimation, startUserGesture } = this.customRouteContext
// ...手势处理逻辑
}
})使用技巧
可在 routeBuilder 中向 CustomRouteContext 添加私有属性,然后在页面中通过 getRouteContext 读取:
const myRouteBuilder = (routeContext) => {
// 添加自定义属性
routeContext.customData = { maxHeight: 500 }
// ...
return { handlePrimaryAnimation }
}
// 页面中读取
Page({
onLoad() {
const ctx = wx.router.getRouteContext(this)
console.log(ctx.customData.maxHeight) // 500
}
})示例代码片段
- 自定义路由完整示例:
y1IbQpmA7wGZ
自定义路由完整指南
概述
Skyline 渲染引擎支持在连续的 Skyline 页面间跳转时实现自定义路由效果。通过 wx.router.addRouteBuilder 注册路由动画定义函数,在 wx.navigateTo 时指定 routeType 触发。
核心接口定义
CustomRouteBuilder
type CustomRouteBuilder = (
routeContext: CustomRouteContext,
routeOptions: Record<string, any>
) => CustomRouteConfigrouteBuilder 函数接收两个参数:
routeContext:路由上下文,包含动画控制器和手势控制方法routeOptions:通过wx.navigateTo({ routeOptions })传入的自定义参数(基础库 3.4.0+)
CustomRouteContext
interface CustomRouteContext {
// 动画控制器,影响推入页面的进入和退出过渡效果
primaryAnimation: SharedValue<number>
// 动画控制器状态
primaryAnimationStatus: SharedValue<number>
// 动画控制器,影响栈顶页面的推出过渡效果
secondaryAnimation: SharedValue<number>
// 动画控制器状态
secondaryAnimationStatus: SharedValue<number>
// 当前路由进度由手势控制
userGestureInProgress: SharedValue<number>
// 手势开始控制路由
startUserGesture: () => void
// 手势不再控制路由
stopUserGesture: () => void
// 返回上一级,效果同 wx.navigateBack
didPop: () => void
}CustomRouteConfig
interface CustomRouteConfig {
// 下一个页面推入后,不显示前一个页面(默认 true)
opaque?: boolean
// 是否保持前一个页面状态(默认 true)
maintainState?: boolean
// 页面推入动画时长,单位 ms(默认 300)
transitionDuration?: number
// 页面推出动画时长,单位 ms(默认 300)
reverseTransitionDuration?: number
// 遮罩层背景色,支持 rgba() 和 #RRGGBBAA(默认空)
barrierColor?: string
// 点击遮罩层返回上一页(默认 false)
barrierDismissible?: boolean
// 无障碍语义(默认空)
barrierLabel?: string
// 是否与下一个页面联动(默认 true)
canTransitionTo?: boolean
// 是否与前一个页面联动(默认 true)
canTransitionFrom?: boolean
// 处理当前页的进入/退出动画,返回 StyleObject
handlePrimaryAnimation?: RouteAnimationHandler
// 处理当前页的压入/压出动画,返回 StyleObject
handleSecondaryAnimation?: RouteAnimationHandler
// 处理上一级页面的压入/压出动画(基础库 3.0.0+)
handlePreviousPageAnimation?: RouteAnimationHandler
// 页面进入时是否采用 snapshot 模式优化(基础库 3.2.0+)
allowEnterRouteSnapshotting?: boolean
// 页面退出时是否采用 snapshot 模式优化(基础库 3.2.0+)
allowExitRouteSnapshotting?: boolean
// 右滑返回时拖动范围是否撑满屏幕(基础库 3.2.0+,默认 false)
fullscreenDrag?: boolean
// 返回手势方向(基础库 3.4.0+,默认 'horizontal')
popGestureDirection?: 'horizontal' | 'vertical' | 'multi'
}
type RouteAnimationHandler = () => { [key: string]: any }AnimationStatus 枚举
enum AnimationStatus {
dismissed = 0, // 动画停在起点
forward = 1, // 动画从起点向终点进行
reverse = 2, // 动画从终点向起点进行
completed = 3, // 动画停在终点
}工作原理
路由生命周期
路由分为 3 个阶段:
1. push 阶段:调用 wx.navigateTo
- B 页
primaryAnimation:0 → 1(进入) - A 页
secondaryAnimation:0 → 1(压入)
2. 手势拖动:用户在 B 页上滑动
- B 页
primaryAnimation随手势变化 - A 页
secondaryAnimation同步变化
3. pop 阶段:调用 wx.navigateBack 或手势返回
- B 页
primaryAnimation:1 → 0(退出) - A 页
secondaryAnimation:1 → 0(恢复)
关键机制:A 页的 secondaryAnimation 值始终与 B 页的 primaryAnimation 值同步变化。
路由联动控制
| 配置项 | 作用 |
|---|---|
canTransitionTo: true | 当前页的 secondaryAnimation 在下一页推入时生效 |
canTransitionTo: false | 当前页推入下一页时不动 |
canTransitionFrom: true | 当前页推入时,前一页的 secondaryAnimation 生效 |
canTransitionFrom: false | 当前页推入时,前一页不动 |
handlePreviousPageAnimation(基础库 3.0.0+)
用于控制上一级页面的压入/压出动画,简化 A 页跳 B 和 C 页使用不同路由动画的场景。
const routeBuilder = (routeContext) => {
const { primaryAnimation } = routeContext
const handlePrimaryAnimation = () => {
'worklet'
// 控制当前页的进入和退出
let t = primaryAnimation.value
return { /* StyleObject */ }
}
const handlePreviousPageAnimation = () => {
'worklet'
// 控制上一级页面的压入和退出
let t = primaryAnimation.value
return { /* StyleObject */ }
}
return {
handlePrimaryAnimation,
handlePreviousPageAnimation
}
}路由上下文对象
在页面或自定义组件中,可通过 wx.router.getRouteContext(this) 获取路由上下文。
Page({
onLoad() {
this.customRouteContext = wx.router.getRouteContext(this)
}
})小技巧:可在 CustomRouteContext 对象上添加私有属性,在 routeBuilder 中设置、在页面中读取。
页面透明背景设置
自定义路由需要前一个页面可见时(如半屏效果),需设置 opaque: false 并配置页面背景透明。
Skyline 下页面背景色层级(4 层)
| 层级 | 设置方式 | 默认值 |
|---|---|---|
| 页面背景色 | WXSS page { background-color: ... } | 白色 |
| 页面容器背景色 | page.json backgroundColorContent | 白色 |
| 自定义路由容器背景色 | StyleObject | 透明 |
| opaque 控制 | CustomRouteConfig.opaque | true(不显示前一页) |
设置透明的方式:
/* WXSS */
page { background-color: transparent; }// page.json
{ "backgroundColorContent": "#ffffff00" }CurveAnimation 工具函数
用于将线性动画进度映射为曲线进度:
const { Easing, derived } = wx.worklet
const Curves = {
linearToEaseOut: Easing.cubicBezier(0.35, 0.91, 0.33, 0.97),
easeInToLinear: Easing.cubicBezier(0.67, 0.03, 0.65, 0.09),
fastOutSlowIn: Easing.cubicBezier(0.4, 0.0, 0.2, 1.0),
fastLinearToSlowEaseIn: Easing.cubicBezier(0.18, 1.0, 0.04, 1.0),
}
function CurveAnimation({ animation, animationStatus, curve, reverseCurve }) {
return derived(() => {
'worklet'
const useForwardCurve = !reverseCurve || animationStatus.value !== AnimationStatus.reverse
const activeCurve = useForwardCurve ? curve : reverseCurve
const t = animation.value
if (!activeCurve) return t
if (t === 0 || t === 1) return t
return activeCurve(t)
})
}版本要求
| 特性 | 最低基础库 |
|---|---|
| 自定义路由基础能力 | 2.29.2 |
| handlePreviousPageAnimation | 3.0.0 |
| 预设路由(7 种) | 3.1.0 |
| allowEnterRouteSnapshotting / allowExitRouteSnapshotting | 3.2.0 |
| fullscreenDrag | 3.2.0 |
| popGestureDirection | 3.4.0 |
| routeConfig / routeOptions | 3.4.0 |
| withOpenContainer | 3.12.2 |
示例代码片段
- 半屏完整示例:
https://developers.weixin.qq.com/s/lg8NoymD7AMK - handlePreviousPageAnimation 示例:
https://developers.weixin.qq.com/s/Dc8ksymP7jM5 - 页面渐显示例:
https://developers.weixin.qq.com/s/rL8dGymj7pMu
路由动画代码模式
模式 1:从右滑入(基础模式)
最简单的自定义路由,页面从右侧滑入。
function SlideRouteBuilder({ primaryAnimation }) {
const { windowWidth } = wx.getWindowInfo()
const handlePrimaryAnimation = () => {
'worklet'
const transX = windowWidth * (1 - primaryAnimation.value)
return {
transform: `translateX(${transX}px)`,
}
}
return { handlePrimaryAnimation }
}
wx.router.addRouteBuilder('slide', SlideRouteBuilder)
wx.navigateTo({ url: 'pageB', routeType: 'slide' })模式 2:半屏弹窗(4 步完整实现)
Step 1:B 页自底向上弹出
const HalfScreenDialogRouteBuilder = (customRouteContext) => {
const { primaryAnimation } = customRouteContext
const { screenHeight } = wx.getWindowInfo()
const handlePrimaryAnimation = () => {
'worklet'
let t = primaryAnimation.value
const topDistance = 0.12
const marginTop = topDistance * screenHeight
const pageHeight = (1 - topDistance) * screenHeight
const transY = pageHeight * (1 - t)
return {
overflow: 'hidden',
borderRadius: '10px',
marginTop: `${marginTop}px`,
height: `${pageHeight}px`,
transform: `translateY(${transY}px)`,
}
}
return { handlePrimaryAnimation }
}Step 2:添加动画曲线
使用 CurveAnimation 使动画更自然,并设置 opaque: false 使前一页可见:
const HalfScreenDialogRouteBuilder = (customRouteContext) => {
const {
primaryAnimation,
primaryAnimationStatus,
} = customRouteContext
const { screenHeight } = wx.getWindowInfo()
const _curvePrimaryAnimation = CurveAnimation({
animation: primaryAnimation,
animationStatus: primaryAnimationStatus,
curve: Curves.linearToEaseOut,
reverseCurve: Curves.easeInToLinear,
})
const handlePrimaryAnimation = () => {
'worklet'
let t = _curvePrimaryAnimation.value
const topDistance = 0.12
const marginTop = topDistance * screenHeight
const pageHeight = (1 - topDistance) * screenHeight
const transY = pageHeight * (1 - t)
return {
overflow: 'hidden',
borderRadius: '10px',
marginTop: `${marginTop}px`,
height: `${pageHeight}px`,
transform: `translateY(${transY}px)`,
}
}
return {
opaque: false,
handlePrimaryAnimation,
}
}Step 3:A 页下沉联动效果
在 A 页的 routeBuilder 中添加 handleSecondaryAnimation:
function ScaleTransitionRouteBuilder(customRouteContext) {
const {
primaryAnimation,
secondaryAnimation,
secondaryAnimationStatus,
} = customRouteContext
const { windowWidth, screenHeight } = wx.getWindowInfo()
const handlePrimaryAnimation = () => {
'worklet'
const transX = windowWidth * (1 - primaryAnimation.value)
return {
transform: `translateX(${transX}px)`,
}
}
const _curveSecondaryAnimation = CurveAnimation({
animation: secondaryAnimation,
animationStatus: secondaryAnimationStatus,
curve: Curves.fastOutSlowIn,
})
const handleSecondaryAnimation = () => {
'worklet'
let t = _curveSecondaryAnimation.value
const scale = 0.08
const topDistance = 0.1
const transY = screenHeight * (topDistance - 0.5 * scale) * t
return {
overflow: 'hidden',
borderRadius: `${12 * t}px`,
transform: `translateY(${transY}px) scale(${1 - scale * t})`,
}
}
return {
handlePrimaryAnimation,
handleSecondaryAnimation,
}
}Step 4:手势返回
在 B 页绑定手势,控制路由动画进度:
<!-- WXML: 在页面左侧放置手势区域 -->
<horizontal-drag-gesture-handler onGestureEvent="handleHorizontalDrag">
<view class="gesture-back-area"></view>
</horizontal-drag-gesture-handler>// GestureState 枚举
const GestureState = {
POSSIBLE: 0,
BEGIN: 1,
ACTIVE: 2,
END: 3,
CANCELLED: 4,
}
Page({
handleDragStart() {
'worklet'
const { startUserGesture } = this.customRouteContext
startUserGesture()
},
handleDragUpdate(delta) {
'worklet'
const { primaryAnimation } = this.customRouteContext
const newVal = primaryAnimation.value - delta
primaryAnimation.value = clamp(newVal, 0.0, 1.0)
},
handleDragEnd(velocity) {
'worklet'
const { primaryAnimation, stopUserGesture, didPop } =
this.customRouteContext
// 判断是否返回:速度大于阈值 → 按速度方向;否则按拖动距离
let animateForward = false
if (Math.abs(velocity) >= 1.0) {
animateForward = velocity <= 0
} else {
animateForward = primaryAnimation.value > 0.5
}
const t = primaryAnimation.value
const animationCurve = Curves.fastLinearToSlowEaseIn
if (animateForward) {
// 恢复到当前页
const duration = Math.min(Math.floor(lerp(300, 0, t)), 300)
primaryAnimation.value = timing(
1.0,
{ duration, easing: animationCurve },
() => {
'worklet'
stopUserGesture()
}
)
} else {
// 返回上一页
const duration = Math.floor(lerp(0, 300, t))
primaryAnimation.value = timing(
0.0,
{ duration, easing: animationCurve },
() => {
'worklet'
didPop()
stopUserGesture()
}
)
}
},
handleHorizontalDrag(gestureEvent) {
'worklet'
const { windowWidth } = wx.getWindowInfo()
if (gestureEvent.state === GestureState.BEGIN) {
this.handleDragStart()
} else if (gestureEvent.state === GestureState.ACTIVE) {
const delta = gestureEvent.deltaX / windowWidth
this.handleDragUpdate(delta)
} else if (gestureEvent.state === GestureState.END) {
const velocity = gestureEvent.velocityX / windowWidth
this.handleDragEnd(velocity)
} else if (gestureEvent.state === GestureState.CANCELLED) {
this.handleDragEnd(0.0)
}
},
})模式 3:下滑返回(纵向手势)
适用于自底向上弹出的页面:
<vertical-drag-gesture-handler onGestureEvent="handleVerticalDrag">
<view class="page-content">
<!-- 页面内容 -->
</view>
</vertical-drag-gesture-handler>Page({
handleVerticalDrag(gestureEvent) {
'worklet'
const { screenHeight } = wx.getWindowInfo()
if (gestureEvent.state === GestureState.BEGIN) {
this.customRouteContext.startUserGesture()
} else if (gestureEvent.state === GestureState.ACTIVE) {
const delta = gestureEvent.deltaY / screenHeight
const { primaryAnimation } = this.customRouteContext
primaryAnimation.value = clamp(primaryAnimation.value - delta, 0.0, 1.0)
} else if (gestureEvent.state === GestureState.END) {
const velocity = gestureEvent.velocityY / screenHeight
// 复用 handleDragEnd 逻辑
this.handleDragEnd(velocity)
} else if (gestureEvent.state === GestureState.CANCELLED) {
this.handleDragEnd(0.0)
}
},
})模式 4:页面渐显效果
const FadeRouteBuilder = ({ primaryAnimation }) => {
const handlePrimaryAnimation = () => {
'worklet'
return {
opacity: primaryAnimation.value,
}
}
return {
opaque: false,
handlePrimaryAnimation,
}
}
wx.router.addRouteBuilder('fade', FadeRouteBuilder)模式 5:使用 handlePreviousPageAnimation
当 A 页跳 B 页和 C 页需要不同的联动效果时:
// C 页的 routeBuilder 同时控制 C 页进入动画和 A 页的联动
const CRouteBuilder = (routeContext) => {
const { primaryAnimation } = routeContext
const handlePrimaryAnimation = () => {
'worklet'
let t = primaryAnimation.value
// C 页自己的进入动画
return { transform: `translateY(${(1 - t) * 100}%)` }
}
const handlePreviousPageAnimation = () => {
'worklet'
let t = primaryAnimation.value
// 控制 A 页的联动效果
return {
transform: `scale(${1 - 0.05 * t})`,
opacity: `${1 - 0.3 * t}`,
}
}
return {
handlePrimaryAnimation,
handlePreviousPageAnimation,
}
}CurveAnimation 和 Curves 工具代码
const { Easing, derived } = wx.worklet
// 预定义曲线
const Curves = {
fastLinearToSlowEaseIn: Easing.cubicBezier(0.18, 1.0, 0.04, 1.0),
linearToEaseOut: Easing.cubicBezier(0.35, 0.91, 0.33, 0.97),
easeInToLinear: Easing.cubicBezier(0.67, 0.03, 0.65, 0.09),
fastOutSlowIn: Easing.cubicBezier(0.4, 0.0, 0.2, 1.0),
}
// AnimationStatus 枚举
const AnimationStatus = {
dismissed: 0,
forward: 1,
reverse: 2,
completed: 3,
}
// 曲线动画封装
function CurveAnimation({ animation, animationStatus, curve, reverseCurve }) {
return derived(() => {
'worklet'
const useForwardCurve =
!reverseCurve || animationStatus.value !== AnimationStatus.reverse
const activeCurve = useForwardCurve ? curve : reverseCurve
const t = animation.value
if (!activeCurve) return t
if (t === 0 || t === 1) return t
return activeCurve(t)
})
}
// 辅助函数
function clamp(value, min, max) {
'worklet'
return Math.min(Math.max(value, min), max)
}
function lerp(a, b, t) {
'worklet'
return a + (b - a) * t
}容器转场动画(open-container)
概述
通过将一个元素无缝地转换为另一个元素,可以加强两个元素间的关系(如瀑布流卡片点击跳转详情页)。基础库提供了 <open-container> 组件来实现该路由效果。
版本要求:
- 开发者工具:Nightly 1.06.2403222
- 基础库:3.4.0
withOpenContainer参数:基础库 3.12.2
基本用法
将需要过渡的元素放置在 <open-container> 组件内,点击组件后使用 navigateTo 跳转下一页面时,对其子节点和下一个页面进行过渡。
WXML
<open-container
closed-elevation="{{closedElevation}}"
closed-border-radius="{{closedBorderRadius}}"
open-elevation="{{openElevation}}"
open-border-radius="{{openBorderRadius}}"
transition-type="{{type}}"
transition-duration="{{duration}}"
bind:tap="goDetail"
>
<card/>
</open-container>JS
Page({
goDetail() {
wx.navigateTo({
url: 'nextPageUrl'
})
}
})组件属性
| 属性 | 类型 | 默认值 | 必填 | 说明 |
|---|---|---|---|---|
| closed-color | string | white | 否 | 初始容器背景色 |
| closed-elevation | number | 0 | 否 | 初始容器影深大小 |
| closed-border-radius | number | 0 | 否 | 初始容器圆角大小 |
| middle-color | string | '' | 否 | fadeThrough 模式下的过渡背景色 |
| open-color | string | white | 否 | 打开状态下容器背景色 |
| open-elevation | number | 0 | 否 | 打开状态下容器影深大小 |
| open-border-radius | number | 0 | 否 | 打开状态下容器圆角大小 |
| transition-duration | number | 300 | 否 | 动画时长(ms) |
| transition-type | string | fade | 否 | 动画类型 |
OpenContainer 实例
OpenContainer 是 open-container 组件对应的 JS 实例对象,可通过 SelectorQuery 获取。
获取实例
Page({
onReady() {
this.createSelectorQuery()
.select('.my-container')
.node()
.exec(res => {
const openContainerInstance = res[0].node
// 可作为 withOpenContainer 参数使用
})
}
})配合 navigateTo 使用
基础库 3.12.2 起,可通过 withOpenContainer 参数指定路由动画所用的 OpenContainer 实例:
Page({
goDetail() {
this.createSelectorQuery()
.select('.my-container')
.node()
.exec(res => {
wx.navigateTo({
url: 'detailPage',
withOpenContainer: res[0].node,
})
})
}
})使用场景
| 场景 | 说明 |
|---|---|
| 瀑布流/卡片列表 | 点击卡片展开到详情页 |
| 图片预览 | 缩略图展开到大图页面 |
| 列表项详情 | 列表项展开到详情页面 |
示例代码片段
- 容器转场示例:
TMOyD8mB7YOB - OpenContainer API 示例:
G3tm7gmP8144
页面返回手势
概述
默认小程序页面都是右滑返回。使用自定义路由和预设路由时,常需要不同的手势返回效果。例如自底向上弹出的页面,纵向滑动返回更符合视觉一致性。
版本要求:
- 开发者工具:Nightly 1.06.2403222
- 基础库:3.4.0
配置属性
在自定义路由配置(CustomRouteConfig)或 wx.navigateTo 的 routeConfig 中设置:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| popGestureDirection | string | horizontal | 返回手势方向 |
| fullscreenDrag | boolean | false | 拖动返回区域是否拓展到全屏范围 |
popGestureDirection 枚举值
| 值 | 说明 |
|---|---|
horizontal | 仅横向拖动返回,fullscreenDrag 仅对横向拖动有效 |
vertical | 仅纵向拖动返回 |
multi | 横向和纵向均可拖动返回 |
使用方式
方式 1:在 routeBuilder 中配置
const myRouteBuilder = (routeContext) => {
// ...动画处理函数
return {
handlePrimaryAnimation,
popGestureDirection: 'vertical',
fullscreenDrag: true,
}
}
wx.router.addRouteBuilder('myRoute', myRouteBuilder)方式 2:在 navigateTo 的 routeConfig 中覆盖
wx.navigateTo({
url: 'xxx',
routeType: 'wx://bottom-sheet',
routeConfig: {
popGestureDirection: 'multi',
fullscreenDrag: true,
}
})routeConfig 会覆盖 routeBuilder 返回的配置项。
结合纵向滚动容器
当使用纵向拖动返回(popGestureDirection: 'vertical' 或 'multi')时,若页面内有纵向滚动的 <scroll-view>,默认在 scroll-view 上滑动无法触发页面返回。
解决方案
声明 scroll-view 的 associative-container 为 pop-gesture,使滑动至顶端后可继续触发页面返回:
<scroll-view
type="custom"
scroll-y
associative-container="pop-gesture"
>
<!-- 页面内容 -->
</scroll-view>工作机制:当 scroll-view 滚动到顶部后继续下拉时,手势会传递给页面返回控制器,触发页面返回动画。
常见场景配置
| 场景 | popGestureDirection | fullscreenDrag |
|---|---|---|
| 默认右滑返回 | horizontal | false |
| 底部弹窗下滑关闭 | vertical | true |
| 半屏多方向关闭 | multi | true |
| 全屏右滑返回 | horizontal | true |
示例代码片段
返回手势示例:BGoSE0mS7KQS
预设路由
概述
基础库预设了一批常见的路由动画效果,降低开发成本。所有预设路由均可通过自定义路由自行实现。
最低基础库版本:3.1.0
预设路由类型
| routeType | 效果说明 | 最低基础库 |
|---|---|---|
wx://bottom-sheet | 底部弹出半屏 | 3.1.0 |
wx://upwards | 自底向上全屏推入 | 3.1.0 |
wx://zoom | 缩放进入 | 3.1.0 |
wx://cupertino-modal | iOS 风格模态卡片 | 3.1.0 |
wx://cupertino-modal-inside | iOS 模态内嵌导航 | 3.1.0 |
wx://modal-navigation | 模态导航 | 3.1.0 |
wx://modal | 模态弹窗 | 3.1.0 |
基本用法
仅需在路由跳转时指定对应的 routeType:
wx.navigateTo({
url: 'xxx',
routeType: 'wx://modal'
})routeConfig 覆盖配置
基础库 3.4.0 起,wx.navigateTo 支持 routeConfig 参数,可覆盖预设路由的默认配置。
wx.navigateTo({
url: 'xxx',
routeType: 'wx://bottom-sheet',
routeConfig: {
fullscreenDrag: true,
popGestureDirection: 'multi'
}
})routeConfig 支持 CustomRouteConfig 中的所有配置项,传入的值会覆盖 routeBuilder 返回的配置。
routeOptions 参数
基础库 3.4.0 起,wx.navigateTo 支持 routeOptions 参数,作为 routeBuilder 的第二个参数传入。开发者可根据当前页面动态改变路由动画内容。
wx.navigateTo({
url: 'xxx',
routeType: 'wx://bottom-sheet',
routeOptions: {
round: false,
height: 80,
}
})wx://bottom-sheet 的 routeOptions
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| round | boolean | true | 是否使用圆角 |
| height | number | 60 | 弹窗页面高度,单位 vh |
结合返回手势
预设路由可结合 routeConfig 自定义返回手势行为:
// 底部弹出 + 纵向拖动返回 + 全屏拖动区域
wx.navigateTo({
url: 'xxx',
routeType: 'wx://bottom-sheet',
routeConfig: {
popGestureDirection: 'vertical',
fullscreenDrag: true,
},
routeOptions: {
height: 70,
}
})低版本降级
低版本基础库会降级到多 WebView 下的默认路由动画(从右向左推入),不会报错。
示例代码片段
预设路由示例:https://developers.weixin.qq.com/s/XC8BGymC7QMo
Related skills
How it compares
Pick skyline-route for Skyline-specific custom routing; use standard mini program navigation docs for non-Skyline WebView pages.
FAQ
What transition types does skyline-route support?
skyline-route supports 7 preset wx:// route types, fully custom routeBuilder animations, and open-container element transitions for card-to-detail effects. The wechat-miniprogram/skyline-skills skill also documents Router API and configurable back gestures.
When should skyline-route be used?
skyline-route should be used when building WeChat Mini Programs on the Skyline renderer that need custom page transitions, half-screen modals, bottom sheets, or gesture-driven returns instead of default navigation.