MotionTransition
受控内容转场,支持门、液体波、光圈、翻转和分层帘
用法
TxMotionTransition 为调用方提供的内容播放转场。modelValue 标识请求显示的视图。默认插槽应使用作用域中的 key:遮挡完成前,它仍指向离场内容。组件不创建路由、页面数据或业务成功状态。
效果与承载模式
| 变体 | 独立结构与轨迹 |
|---|---|
spatial-door-portal | 两片门以外侧为铰链,透视旋转 ±85°,横向移动 ±10%。先合拢遮挡旧内容,再打开呈现新内容。 |
french-doors-3d | 两片门以中缝为铰链,旋转 ±90°,包含内嵌门板和透明度变化。铰链方向与空间双门不同。 |
obsidian-liquid-wave | 三层三次贝塞尔波,每层有 14 个独立延迟的控制点。前沿上升遮挡,后沿上升揭示。 |
radial-iris-mask | 中央圆形遮罩从 0% 扩展至 150%,然后收回。 |
perspective-flip-stage | 真实内容绕 X 轴翻出,在侧立时替换,再翻入。缩放从 0.85 回到 1,并同步透明度。 |
staggered-glass-curtain | 五列磨砂帘依次下落,继续向下离场,揭示新内容。 |
double-stairs | 五列从上下两侧交错进入,依次遮挡,再从相反方向离场。 |
liquid-wave | Registry 的三层波,每层有 12 个独立延迟的贝塞尔控制点。 |
cross-fade | 旧内容先淡出,新内容再淡入。Registry 的通用透明度行为只保留一个公共名称。 |
inline 提供无外框的内容舞台。card 增加使用主题令牌的表面、头部和底部。modal 居中显示限宽弹窗,overlay 填满可见视口。两种弹层模式都 Teleport 到 body,复用共享叠层分配器并限制焦点范围。演示用卡片展示全部九种效果,也支持为行内、弹窗和全屏选择任意效果。输入框里的文字直接进入插槽,完成标签读取真实事件。
最佳实践
- 用插槽的
key选择内容,不要直接读取正在变化的外部模型。内容标识放在modelValue,显示状态放在v-model:open。 - 关闭时保持组件挂载。设置
open=false,不要给TxMotionTransition外层加v-if。关闭会提交待显示内容并恢复焦点,弹层容器保留淡出、缩放与下移离场;离场节点立即退出焦点与最上层弹窗判断。减少动态效果或显式立即提交时不延迟移除。 - 连续修改模型会打断上一轮,最终显示最新请求。
replay()、replayKey和修改variant都能在内容标识不变时重播。 - 如果交互允许打断,不要在播放时禁用触发按钮。运动中的内容子树会暂时设为 inert,头部和底部操作仍可用。
- 来源卡片的悬停预览用原生
@mouseenter更新调用方内容模型。演示在播放时忽略悬停,同时提供可用键盘操作的按钮。 - 为
title、ariaLabel和closeLabel提供本地化文案。自定义头部时,弹窗用ariaLabel作为可访问名称。 - 尊重系统的减少动态效果偏好。
disabled=true或duration=0提供显式立即提交路径,不延迟内容状态,也不伪造业务成功。
API 参考
属性
| 名称 | 类型 | 默认值 | 说明 |
|---|---|---|---|
modelValue | string | number | 必填 | 请求显示的内容标识,不是弹窗显示状态。 |
variant | MotionTransitionVariant | 'spatial-door-portal' | 上述九个 ID 之一。MOTION_TRANSITION_VARIANTS 导出完整列表。 |
mode | 'inline' | 'card' | 'modal' | 'overlay' | 'inline' | 内容承载模式。 |
open | boolean | false | modal/overlay 的受控显示状态,inline/card 忽略此属性。 |
transition | 'snappy' | 'smooth' | 'bouncy' | SpringConfig | { duration: number; ease?: string } | 'smooth' | 已有 liquid 共享弹簧或时序定义。 |
duration | number | 共享弹簧时长 | 离场与进场的总时长,单位为毫秒。零表示立即提交。 |
speed | number | 1 | 播放速率,2 将总时长减半。 |
replayKey | string | number | — | 修改后重播当前内容转场。 |
disabled | boolean | false | 立即提交,不播放动画。 |
title | string | '' | 默认头部标题及弹窗可访问标题。 |
ariaLabel | string | 'Content transition' | 无默认标题或使用自定义头部时的弹窗名称。 |
closeLabel | string | 'Close' | 关闭按钮的可访问标签。 |
closable | boolean | true | 显示弹窗关闭按钮,不阻止 API 或 Escape 关闭。 |
maskClosable | boolean | true | 点击弹窗背景时关闭。 |
escapeClosable | boolean | true | 允许最上层弹窗响应 Escape。 |
width | string | '640px' | modal 宽度,最大不超过视口。 |
size | 'xs' | 'sm' | 'md' | 'lg' | 'md' | 头部、内容和底部的间距。 |
事件
| 事件 | 参数 | 说明 |
|---|---|---|
update:open | boolean | 用 false 请求关闭受控弹窗。 |
start | { from, to, variant, reason } | 每个接受的内容转场一次。reason 为 change、replay 或 open。 |
completed | { from, to, variant, reason, status } | 内容子树提交后发出一次。状态为 finished、interrupted、reduced、inactive 或 closed。 |
interrupted | 相同完成对象 | 新请求替换上一轮时,在 completed 前发出。 |
close | 'button' | 'escape' | 'mask' | 'api' | 弹窗关闭请求,调用方须同步 open。 |
inactive 包含显式禁用、零时长、内容移出可见区域、文档隐藏和 KeepAlive 停用。打断时先提交上一轮目标,再开始新请求,最后请求决定最终画面。完成事件只表示界面转场,不表示网络、保存或导航操作成功。卸载会取消待执行回调,不从已销毁组件发出事件。
插槽与方法
| 插槽 | 作用域 | 说明 |
|---|---|---|
default | { key, phase, running, close, replay } | 真实内容,phase 为 idle、leave 或 enter。 |
header | 相同作用域 | 自定义头部,内置关闭按钮仍单独保留。 |
footer | 相同作用域 | 常驻操作和完成状态,位于暂时 inert 的内容子树外。 |
| 暴露方法 | 说明 |
|---|---|
replay() | 使用当前模型和变体重播。 |
finish() | 提交当前目标,发出状态为 finished 的 completed。 |
close() | 提交待显示内容,并请求关闭受控弹窗。 |
CSS 变量
| 变量 | 默认值 | 说明 |
|---|---|---|
--tx-motion-transition-surface | --tx-bg-color-overlay | 门、光圈和最上层波的实色表面。 |
--tx-motion-transition-pad | 随 size 变化,md 为 16px | 内容、头部和底部间距。 |
--tx-motion-transition-radius | 随 size 变化,md 为 16px | card/modal 圆角。 |
--tx-motion-transition-width | 弹层模式的 width 属性 | modal 宽度。弹层优先用属性设置。 |
概述
离场阶段保留旧插槽子树。遮挡完成后,移除旧子树并挂载请求的内容。进场揭示新内容,Vue 提交后再发出 completed。液体波保留分层控制点延迟,门保留各自的铰链结构。翻转和淡化直接作用于真实视图,不使用品牌占位图。
内容内的操作触发替换时,焦点先移至舞台,完成后移至新内容的首个可聚焦元素。打开弹窗时焦点进入弹窗。只有最上层弹窗处理 Tab 和 Escape。关闭后,焦点回到仍连接文档的打开按钮,不滚动页面。减少动态效果或失活会停止唯一 RAF,并提交目标。停用或卸载时释放监听器、观察器和待执行帧。useId 提供稳定的舞台、标题 ID 和确定性的波延迟种子,兼容服务端渲染与 hydration。
技术实现
来源为 Amicro 提交 43c29ce,MIT,Copyright (c) 2026 SYED SUBHAN UDDIN。src/data/transitions.ts:23~199 提供六个目录实现。src/components/PageTransitionOverlay.tsx:25~196 提供 14 点预览波、门的铰链、光圈、翻转和帘结构。PageTransitionCard.tsx 对应 card 预览与重播。PageTransitionModal.tsx 对应弹窗预览、重复触发和播放速率。PageTransitionOverlay.tsx 对应可复用舞台。品牌文案、源码复制展示和路由归属不属于组件业务能力。
Registry 文件 registry/ui/transitions/page-transition.tsx:4~22 声明了 18 个名称,但第 88~135 行只实现阶梯和液体波。第 137~143 行为其他名称提供同一透明度兜底。以下逐项映射保留来源覆盖,不宣称 16 个独立效果,也不导出旧名称别名:
| 上游声明名 | 真实源码行为 | 公共映射 |
|---|---|---|
double-stairs | 五列交错阶梯,第 88~120 行 | double-stairs |
shutter-stairs | 上游只有透明度 fallback | cross-fade |
split-stairs | 上游只有透明度 fallback | cross-fade |
horizontal-split | 上游只有透明度 fallback | cross-fade |
vertical-split | 上游只有透明度 fallback | cross-fade |
slash | 上游只有透明度 fallback | cross-fade |
lattice | 上游只有透明度 fallback | cross-fade |
curtain-shred | 上游只有透明度 fallback | cross-fade |
pixel | 上游只有透明度 fallback | cross-fade |
pixel-wave | 上游只有透明度 fallback | cross-fade |
pixel-spiral | 上游只有透明度 fallback | cross-fade |
vortex | 上游只有透明度 fallback | cross-fade |
cross-fade | 上游只有透明度 fallback | cross-fade |
expand-grow | 上游只有透明度 fallback | cross-fade |
push-slide | 上游只有透明度 fallback | cross-fade |
pop-over | 上游只有透明度 fallback | cross-fade |
depth-forward | 上游只有透明度 fallback | cross-fade |
liquid-wave | 三层 12 点贝塞尔波,第 39~84 和 123~135 行 | liquid-wave |
实现复用已有 resolveTransition、easingFunction 共享弹簧和 useMotionActivity,不引入 React、Framer Motion 或 Tailwind 运行时。真实遮挡中点和动画结束替代来源中固定 380/850 ms 的内容切换定时器。构建、自动化测试和真实浏览器验收由集成阶段执行,本页不宣称这些检查已通过。