Transition 过渡
Vue 风格的 <Transition>、按 key 切换的视图切换器与 <TransitionGroup>,基于 ArkUI 组件转场(TransitionEffect.asymmetric + if / ForEach 的 key)。时序来自 SparkAnim:--motion-transition-* 可配置,关闭动效后所有切换立即完成。
过渡完全是动画效果,网页预览无法还原,本页示例只展示代码。请在 HarmonyOS 设备或画廊应用中查看实际效果。
显示 / 隐藏
STransition 根据 show(相当于 v-if)挂载与移除内容。生命周期事件:onBeforeEnter、onAfterEnter、onBeforeLeave、onAfterLeave。
@Local open: boolean = true;
SButton({ text: 'Toggle' }).onClick(() => this.open = !this.open)
STransition({ show: this.open, name: 'slide-down', distance: '24vp',
onAfterEnter: () => { ... }, onAfterLeave: () => { ... } }) {
DemoPane({ title: 'Hello', body: '...' })
}切换过渡
SSwitchTransition 渲染 pageBuilder(current),并在新旧视图之间做动画;只有在过渡进行时两者才同时挂载。mode 为 'out-in' / 'in-out' 时依次执行,'default' 同时执行。切换到 order 中更靠前的 key 时,带方向的预设会反向。
@Local view: string = 'inbox';
@LocalBuilder
renderView(key: string) {
// build from the key argument, so the leaving view keeps its own content
DemoPane({ title: key, body: '...' })
}
SSwitchTransition({
current: this.view,
pageBuilder: this.renderView,
name: 'shared-axis-x', // fade | slide-* | scale | zoom | fade-through | shared-axis-x/y/z | none
mode: 'out-in', // 'default' (simultaneous) | 'out-in' | 'in-out'
order: ['inbox', 'drafts', 'sent'], // navDirection 'auto': later key = forward
onBeforeLeave: (k: string) => { ... },
onAfterEnter: (k: string) => { ... }
})页面过渡
SPageTransition 是页面级的切换器(RouterView + Transition):默认是 X 轴共享轴动画,方向取自 index、order 或访问历史。用同样的方式包裹画廊的 DocContent,即可在文档页面之间切换时产生动画。
// Vue: <RouterView v-slot="{ Component }"><Transition name="slide-left">…
@Local step: number = 0;
@LocalBuilder
renderStep(key: string) { DemoPane({ title: key }) }
SPageTransition({
current: STEPS[this.step],
index: this.step, // or order: STEPS, or neither (visit history: going back = back)
pageBuilder: this.renderStep,
name: 'slide-left' // default 'shared-axis-x'
})
SButton({ text: 'Back' }).onClick(() => this.step--) // reverses the slide
SButton({ text: 'Next' }).onClick(() => this.step++)
// gallery shell (pages/Index.ets): animate between doc pages
@LocalBuilder renderPage(key: string) { DocContent({ page: key }) }
SPageTransition({ current: this.page, pageBuilder: this.renderPage, order: NAV_ORDER, name: 'fade-through' })自定义效果与时序
enterEffect / leaveEffect 接受任意 TransitionEffect(继承解析出的时长与曲线);duration 与 ease 可按实例覆盖动效 key。
STransition({
show: this.open,
duration: 600, // per-instance override (ms); motion off still wins
ease: 'spring(0.5, 0.7)',
enterEffect: (env: SparkTransitionEnv) => TransitionEffect.rotate({ z: 1, angle: -90 })
.combine(TransitionEffect.scale({ x: 0.5, y: 0.5 })).combine(TransitionEffect.OPACITY),
leaveEffect: (env: SparkTransitionEnv) => TransitionEffect.translate({ x: 120 })
.combine(TransitionEffect.OPACITY)
}) { ... }
// theme: --motion-transition-duration: 300ms; --motion-transition-ease: ease-out;
// --motion-page-transition-*, --motion-transition-group-*; --motion-enabled: false → instant过渡组
STransitionGroup 为插入和移除的条目做动画;其余条目通过布局动画移动到新位置(相当于 Vue 的 FLIP move)。
@Local ids: string[] = ['Apple', 'Banana', 'Cherry'];
@LocalBuilder
renderItem(key: string) { DemoRow({ text: key }) }
STransitionGroup({ items: this.ids, itemBuilder: this.renderItem, name: 'slide-left', distance: '40vp', gap: 8 })
// assign a new array: insert / remove animate, the other rows glide to their new place
this.ids = [...];API
从组件库源码中的 @Param / @Event / @BuilderParam 声明自动提取。
SSwitchTransition
按键切换的内容切换器(Vue 的 <Transition mode> 包裹 <component :is> / <RouterView v-slot>):渲染 pageBuilder(current),当 current 变化时,从旧视图动画过渡到新视图。两个视图仅在过渡进行时挂载(ForEach 按 key 的插槽 + .transition(TransitionEffect.asymmetric(...)))。
pageBuilder接收 key;请根据该参数构建视图(而不是根据父组件状态),这样离开的视图会保留其内容。请使用@LocalBuilder,使this仍指向父组件。mode:'default'(同时进行,视图在 Stack 中叠加)、'out-in'(先离开旧视图,再进入新视图)、'in-out'(先进入新视图,再离开旧视图)。navDirection(之所以如此命名,是因为direction是通用属性):'forward' | 'back' | 'auto'。'auto' 依次比较index(数字,例如标签索引)、order中的位置,然后是访问历史(返回上一个 key 即为后退)。带方向的预设(slide-、zoom、shared-axis-)在后退时会反向。- 生命周期事件接收 key:onBeforeEnter / onAfterEnter / onBeforeLeave / onAfterLeave。
clipContent(默认 true)会将滑动的视图裁剪到切换器的边界之内。
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
current | string | '' | |
name | SparkTransitionName | 'fade' | |
mode | SparkTransitionModeSparkTransitionMode = 'default' | 'out-in' | 'in-out' | 'default' | |
navDirection | SparkNavDirectionSparkNavDirection = 'forward' | 'back' | 'auto' | 'auto' | |
order | string[] | [] | 供 navDirection: 'auto' 使用的有序 key(靠后的为前进)。 |
index | number | -1 | current 的数字位置,供 navDirection: 'auto' 使用(-1 表示不使用)。 |
appear | boolean | false | |
distance | string | '100%' | |
clipContent | boolean | true | |
motionKey | string | 'transition' | |
speed | SparkSpeedSparkSpeed = 'fast' | 'normal' | 'slow' | 'normal' | |
duration | number | -1 | |
ease | string | '' | |
enterEffect | SparkTransitionEffectFactory | undefined | undefined | |
leaveEffect | SparkTransitionEffectFactory | undefined | undefined |
| 事件 | 类型 | 默认值 | 说明 |
|---|---|---|---|
onBeforeEnter | (key: string) => void | () => { } | |
onAfterEnter | (key: string) => void | () => { } | |
onBeforeLeave | (key: string) => void | () => { } | |
onAfterLeave | (key: string) => void | () => { } |
插槽: pageBuilder
SPageTransition
页面级的 SSwitchTransition(Vue 的 <RouterView v-slot="{ Component }"><Transition :name>):默认采用带方向的 Material 共享轴 X 动画;除非提供了 order / index,否则根据访问历史判断是否为后退。
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
current | string | '' | |
name | SparkTransitionName | 'shared-axis-x' | |
mode | SparkTransitionModeSparkTransitionMode = 'default' | 'out-in' | 'in-out' | 'default' | |
navDirection | SparkNavDirectionSparkNavDirection = 'forward' | 'back' | 'auto' | 'auto' | |
order | string[] | [] | |
index | number | -1 | |
appear | boolean | false | |
distance | string | '100%' | |
clipContent | boolean | true | |
motionKey | string | 'page-transition' | |
speed | SparkSpeedSparkSpeed = 'fast' | 'normal' | 'slow' | 'normal' | |
duration | number | -1 | |
ease | string | '' | |
enterEffect | SparkTransitionEffectFactory | undefined | undefined | |
leaveEffect | SparkTransitionEffectFactory | undefined | undefined |
| 事件 | 类型 | 默认值 | 说明 |
|---|---|---|---|
onBeforeEnter | (key: string) => void | () => { } | |
onAfterEnter | (key: string) => void | () => { } | |
onBeforeLeave | (key: string) => void | () => { } | |
onAfterLeave | (key: string) => void | () => { } |
插槽: pageBuilder
STransition
用于单个条件元素(v-if)的 Vue <Transition>:show 变化时插入 / 移除内容,并通过官方的组件转场(.transition(TransitionEffect.asymmetric(...), onFinish))做动画。
时序:动效 key motionKey(默认 'transition',--motion-transition-duration\|ease\|enabled),按 speed 生效,可通过 duration(毫秒)/ ease 按实例覆盖;--motion-enabled: false 会使其立即完成。键控内容(在页面 / 视图之间切换)请使用 SSwitchTransition;列表请使用 STransitionGroup。
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
show | boolean | false | 挂载(true)或移除(false)内容。 |
name | SparkTransitionName | 'fade' | |
appear | boolean | false | 初次渲染时同样执行动画(Vue 的 appear)。 |
distance | string | '100%' | 'slide-*' 预设的滑动距离(长度字符串;默认为内容的 100%)。 |
motionKey | string | 'transition' | |
speed | SparkSpeedSparkSpeed = 'fast' | 'normal' | 'slow' | 'normal' | |
duration | number | -1 | 按实例设置的时长,单位毫秒(-1 表示由动效 key 决定)。 |
ease | string | '' | 按实例设置的缓动('ease-out'、'cubic-bezier(...)'、'spring(0.4, 0.8)');'' 表示由动效 key 决定。 |
enterEffect | SparkTransitionEffectFactory | undefined | undefined | |
leaveEffect | SparkTransitionEffectFactory | undefined | undefined |
| 事件 | 类型 | 默认值 | 说明 |
|---|---|---|---|
onBeforeEnter | () => void | () => { } | |
onAfterEnter | () => void | () => { } | |
onBeforeLeave | () => void | () => { } | |
onAfterLeave | () => void | () => { } |
插槽: 子组件(尾随闭包)
STransitionGroup
Vue 的 <TransitionGroup>:按 key 排列的列表,插入 / 移除的条目使用预设(或自定义效果)做动画,其余条目则平滑滑动到新位置(Vue 的 FLIP move 类)。移动是 ArkUI 的布局动画:渲染后的列表会在 SparkAnim.runWith(animateTo + applySync)内更新,因此更新导致的位置变化与之使用相同的时长 / 曲线。
请通过赋值新数组来更新 items(this.ids = [...]);key 必须唯一且稳定。
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
items | string[] | [] | |
name | SparkTransitionName | 'fade' | |
axis | SparkTransitionGroupAxisSparkTransitionGroupAxis = 'vertical' | 'horizontal' | 'vertical' | |
gap | number | 0 | |
distance | string | '100%' | 'slide-*' 预设的滑动距离(默认为条目的 100%)。 |
motionKey | string | 'transition-group' | |
speed | SparkSpeedSparkSpeed = 'fast' | 'normal' | 'slow' | 'normal' | |
duration | number | -1 | |
ease | string | '' | |
enterEffect | SparkTransitionEffectFactory | undefined | undefined | |
leaveEffect | SparkTransitionEffectFactory | undefined | undefined |
插槽: itemBuilder