动力 · 15
定时补间
Tween · tween在固定时间内从当前值走向目标,半途改目标也不断层。
补间适合明确的界面状态切换。新点击发生在旧动画中途时,如果下一段仍从最早的起点开始,元素会突然跳回去。重新设起点为当前显示值,才能让多次操作接成一条连续轨迹。
公式
p = ease(clamp(elapsed / duration)) value = lerp(from, to, p) on retarget: from ← current; to ← next; elapsed ← 0
参数
| 本页默认 | 成熟实现 | |
|---|---|---|
| duration | 0.45 s | — |
| ease | power(3, out) | GSAP power eases |
怎样做好
- 中途换目标时从当前可见值出发;不要沿用第一次操作时的起点。
- 将时间归一化后再缓动,缓动只塑造进度,不改变补间时长。
- 若同一属性同时由拖动和补间写入,明确谁拥有控制权;按下时应停止或重新定向补间。
在我们的案例里
67 个案例用到补间。folio 的索引和标题轨道逐帧更新,摘要又启动 GSAP 补间;同一视图的持续运动与短暂过渡需要各自清楚的状态来源。
出现在 67 个案例
01Momentum Slider02Drag Gallery03Formation04Cardwall05Riffle06Revolver07Rotunda08Iris09Lens Bloom10Frieze11Aperture12Folio13Cinema Reel14Stream Showcase15Hardback16Picasso Ecommerce17Assembly18Fathom
+49 更多
19Emulsion20Portfolio Photographer21Reverie22Boutique23Nova24Alive25Shape Trail26Membrane27Liquid Type28Filament29Pixels30Cipher31Console32Cutout33Crema34Aster35Spring36Benchmark37Amour38Fluid Gallery39Marathon40Atelier41Desk 9542Isle43Pantheon44Atlas47Overworld48Moments49Burst50Dimension51Morph52Meow53Relay54Lumen55Serene56Fleur57Atrium58Skyward59Helix60Crate61Prism62Flashlight63Viewfinder64Sand65Arrange66Tunnel67Reel68Type69Loupe
参考实现 · basics.js
/** Progress of a tween at time t (seconds since start): delay, then duration, eased. Pure. */
export const tweenProgress = (t, { delay = 0, duration = 1, ease = power(3) } = {}) =>
ease(clamp((t - delay) / duration));
/**
* A tween that can be interrupted: retarget() starts from the CURRENT value,
* so a second click mid-flight never jumps back to the old start.
*/
export class Tween {
constructor({ value = 0, duration = 0.4, ease = power(3) } = {}) {
Object.assign(this, { value, duration, ease }); this.from = this.to = value; this.t = 1;
}
retarget(to) { this.from = this.value; this.to = to; this.t = 0; }
step(dt) {
if (this.t >= 1) return this.value;
this.t = Math.min(1, this.t + dt / this.duration);
this.value = lerp(this.from, this.to, this.ease(this.t));
return this.value;
}
}