Transition
Transition 基础原型
这段 Demo 展示纯命令式控制状态机。
- Enter:从任意状态进入
entering(合法路径为closed → entering或leaving → entering);若已在进入中则忽略。 - Leave:从任意状态进入
leaving(合法路径为entered → leaving或entering → leaving);若已在离开中则忽略。 - Complete:将
entering推进到entered,或将leaving推进到closed。
典型完整操作链路:
Enter → Complete → Leave → Complete这段 Demo 展示通过 open prop 受控驱动状态机。Transition 使用 enterDuration / leaveDuration 作为中立的延时完成机制;宿主也可以在原生动画结束时主动调用 complete() 提前完成。
- Toggle Open:翻转
open值。- 若当前是
closed/leaving,切到open=true会进入entering → entered。 - 若当前是
entered/entering,切到open=false会进入leaving → closed。
- 若当前是
- Click Me:点击 Box 本身也能触发 Toggle Open,与按钮行为一致。
典型操作链路:
Toggle Open(显示)→ Toggle Open(隐藏)在 Demo 中 CSS 设置了 0.3s 过渡,因此 entering 和 leaving 状态会在对应时长后自动 complete。
Transition 是一个底层基础组件,用于管理元素的存在状态生命周期。它本身不渲染可见内容,而是提供状态机治理,让宿主平台(CSS、React、Vue 等)根据状态驱动实际动画。
asTransition() 是由 @proto.ui/prototypes-base 导出的无参数 ordinary once asHook。同一 setup chain 重复调用会返回同一个投射 handle。它只治理 closed / entering / entered / leaving 这组感知状态,并通过 run.lifecycle.setPresent() 向 L1 ViewIntent 提交结构意图。
它不再需要 module port 或宿主私有 facade。生命周期回调、run.lifecycle.setPresent() 与 Core delay() 已构成实现该策略所需的完整公开能力边界。
Transition、ViewIntent 与实际 view epoch 是三个不同事实:
transitionState:closed → entering → entered → leaving → closedViewIntent: detached ↔ presentview epoch: detached ↔ mounting ↔ mounted ↔ unmounting- 进入:先把 ViewIntent 设为 present;新 view epoch mounted 后才进入
entering,避免暴露尚未完成首次提交的 DOM。 - 离开:
leaving全程保留当前 view;完成到closed后才把 ViewIntent 设为 detached。 - 复原:detach 不会销毁 Proto instance。controls、state 与 props watcher 仍然存活,后续
open=true或enter()可以重建新的 view epoch。
这让状态机能与 CSS 过渡正确配合:即便适配器原本会立即移除元素,entering 和 leaving 阶段也能保证 DOM 元素始终存在。
与 lifecycle ViewIntent 的关系
Section titled “与 lifecycle ViewIntent 的关系”ViewIntent 是 Transition 唯一使用的结构意图通路。isPresent 只表示感知存在性,closed 也不等价于 Proto instance 已销毁。
- RuntimeSession 在 detached 时仍同步 props 并派发 watcher,因此受控
open=false → true可以请求自己的 view,不会形成“先 mount 才能读取 open”的死锁。 - Adapter owner 保留 Proto instance,并按最新 ViewIntent 创建或释放 React、Vue 或 WC 的 view epoch。
- Reveal barrier 保证新 view 完成首次 commit 与 effects replay 后才可见,不再依赖 React/Vue 的双 RAF baseline。
这种分离带来的好处是:
- Transition 使用者只关心状态机。 结构协调由
run.lifecycle.setPresent()完成,不需要直接操作 adapter。 - 适配器只关心 ViewIntent 与 view epoch。 React、Vue 和 WC 不需要识别
entering与entered的业务区别。 - Proto instance 可以跨 view epoch 存活。 React/Vue 可以渲染
null,WC 可以释放内部 view;两者都不会因此丢失 controls 与原型状态。
1. 始终将状态变化与 CSS 过渡配对使用
Section titled “1. 始终将状态变化与 CSS 过渡配对使用”Transition 只管理逻辑状态。如果你没有为 data-transition-state="entering" 和 data-transition-state="leaving" 提供 CSS,元素在 complete() 被调用时就会瞬间出现或消失。
2. 使用 duration fallback,并可接入宿主完成信号
Section titled “2. 使用 duration fallback,并可接入宿主完成信号”默认情况下 Transition 会在 enterDuration / leaveDuration 后完成。若宿主动画实际更早结束,可以监听完成事件并调用 controls.complete();旧的延时任务会被取消。
典型的受控模式写法:
// 设置 open=true 并应用 CSS 过渡后el.addEventListener('transitionend', () => { exposes.controls.complete();});3. 需要挂载时播放动画请使用 appear
Section titled “3. 需要挂载时播放动画请使用 appear”如果你希望组件在首次渲染时就能播放进入动画,请设置 appear: true。否则组件会在挂载时直接跳到 entered,不会播放进入动画。
4. 根据交互体验选择中断策略
Section titled “4. 根据交互体验选择中断策略”'reverse'(默认):适合大多数 UI(菜单、提示框)。用户快速开关时,动画会平滑反向播放。'wait':适合必须保证每场动画都完整走完的场景(例如分步向导的背景面板不应跳过动画)。'immediate':适合对瞬时状态切换要求高的场景。当前动画会被丢弃,新动画从干净状态重新开始。
5. 不要直接修改 transition 状态
Section titled “5. 不要直接修改 transition 状态”始终通过暴露的 controls(controls.enter()、controls.leave()、controls.complete())或 open prop 来驱动状态。直接修改 transitionState 会绕过状态机与 ViewIntent 的顺序约束。
6. 在 leaving 期间保持 DOM 子树稳定
Section titled “6. 在 leaving 期间保持 DOM 子树稳定”Transition 会在 leaving 阶段保留当前 view,请避免提前销毁子元素状态(例如拆毁 <video> 元素或取消网络请求),直到状态到达 closed 或收到真正的 view unmount 生命周期。
closed → entering → entered → leaving → closed- closed: 感知上不可见;通常会请求 ViewIntent detached,但不表示 Proto instance 已销毁
- entering: 进入动画中,DOM 存在,应用进入样式
- entered: 完全可见,稳定状态
- leaving: 离开动画中,DOM 仍存在,应用离开样式
| Prop | 类型 | 默认值 | 说明 |
|---|---|---|---|
open | boolean | - | 受控模式:目标存在状态 |
defaultOpen | boolean | false | 非受控模式:初始状态 |
appear | boolean | false | 是否在挂载时播放进入动画 |
enterDuration | number | 300 | 进入动画预期时长(ms) |
leaveDuration | number | 200 | 离开动画预期时长(ms) |
interrupt | 'reverse' | 'wait' | 'immediate' | 'reverse' | 中断策略 |
命令式 API
Section titled “命令式 API”通过 controls expose 访问:
enter(): 触发进入leave(): 触发离开complete(): 标记当前过渡完成,推进到下一状态
v0 范围说明
Section titled “v0 范围说明”base-transition v0 仅管理单个元素自身的存在状态生命周期(closed → entering → entered → leaving → closed)。
若需要 parent/child 嵌套协调退出(例如外层 Dialog 等待内层某个子元素先完成离开动画后再关闭),这属于 transition-group / boundary 类的独立抽象,不在当前 v0 范围内。