ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

Remix UI Tween API 全解析:基于生成器的三次贝塞尔补间动画

Remix UI Tween API 全解析:基于生成器的三次贝塞尔补间动画 Remix UI Tween API 全解析基于生成器的三次贝塞尔补间动画【免费下载链接】remixThe fully-stacked web framework项目地址: https://gitcode.com/GitHub_Trending/re/remixtween是 Remix UIremix-run/uianimation模块中基于 ES 生成器实现的补间动画原语用于在指定时长内以三次贝塞尔缓动曲线将数值从from插值到to并通过requestAnimationFrame逐帧驱动。本指南以 Tween API 文档 为主线结合 tween.ts 源码讲解其生成器协议、贝塞尔数学内核、内置缓动预设与自定义曲线并给出命令式动画、组件内自动清理以及多属性动画的完整实战方案。读完本文你将能熟练用tween驱动 Canvas/WebGL、非 CSS 属性与序列化复杂动画并在 Remix UI 组件中安全接入handle.signal生命周期。认识tween一次一行得到一个动画生成器tween的调用形态非常简洁——传入from、to、duration与curve四个选项返回一个可逐步推进的生成器generatorimport { tween, easings } from remix/ui/animation let animation tween({ from: 0, to: 100, duration: 1000, curve: easings.easeInOut, }) // Initialize generator animation.next() function animate(timestamp: number) { let { value, done } animation.next(timestamp) element.style.transform translateX(${value}px) if (!done) requestAnimationFrame(animate) } requestAnimationFrame(animate)注意两个关键步骤先手动调用一次animation.next()不带参数完成生成器初始化让 tween 有机会先yield出起始值from之后每一帧调用animation.next(timestamp)把requestAnimationFrame回调收到的时间戳传回生成器内部作为计算进度的依据。从 tween.ts 的实现看生成器内部维护startTime第一次收到时间戳时记录与当前value然后进入while (true)循环先yield value交出当前插值结果等外部调用next(timestamp)时再计算elapsed从而形成“帧回调 - 生成器 - 新值”的双向数据流。工作原理生成器协议与三次贝塞尔数学文档用三条规则概括tween的行为每次迭代yield当前插值后的数值通过next(timestamp)接收当前时间戳当duration耗尽后返回done: true。其核心思想是“用三次贝塞尔曲线把线性的时间进度映射为缓动后的数值进度”这与 CSS 的cubic-bezier()时间函数完全一致。源码将这一数学过程拆成三个函数cubicBezier(t, p1, p2)tween.ts#L38-L42三次贝塞尔求值公式B(t) 3(1-t)²t·p1 3(1-t)t²·p2 t³。由于 CSS 风格贝塞尔固定以(0,0)为起点、(1,1)为终点只需传入两个中间控制点的坐标cubicBezierDerivative(t, p1, p2)tween.ts#L51-L55贝塞尔导数B(t) 3(1-t)²·p1 6(1-t)t·(p2-p1) 3t²·(1-p2)为求根迭代提供斜率solveCubicBezierX(x1, x2, targetX)tween.ts#L9-L27已知 x 轴时间进度反解参数 t使用Newton-Raphson 迭代以t targetX作初始猜测通常 4~8 次迭代即可收敛源码固定迭代 8 次并在斜率或误差小于1e-6时提前退出最后把结果钳制在[0, 1]区间。主生成器 tween 的推进逻辑为let elapsed timestamp - startTime let linearProgress Math.min(elapsed / duration, 1) // x 轴 时间y 轴 数值 let t solveCubicBezierX(x1, x2, linearProgress) let easedProgress cubicBezier(t, y1, y2) value from (to - from) * easedProgress if (linearProgress 1) { return to }可以看到linearProgress被钳制在1以内当进度到达1时生成器直接return to此时done为true、value精确等于目标值不会出现过冲overshoot——这正是tween与下文物理弹簧spring的本质区别。内置缓动预设easingseasings是一个包含常用三次贝塞尔控制点的常量对象控制点数值与 CSS 时间函数一一对应定义见 tween.ts#L75-L81import { easings } from remix/ui/animation easings.linear // { x1: 0, y1: 0, x2: 1, y2: 1 } easings.ease // { x1: 0.25, y1: 0.1, x2: 0.25, y2: 1 } easings.easeIn // { x1: 0.42, y1: 0, x2: 1, y2: 1 } easings.easeOut // { x1: 0, y1: 0, x2: 0.58, y2: 1 } easings.easeInOut // { x1: 0.42, y1: 0, x2: 0.58, y2: 1 }预设控制点 (x1, y1, x2, y2)行为描述linear(0, 0, 1, 1)无缓动匀速ease(0.25, 0.1, 0.25, 1)CSS 默认 easeeaseIn(0.42, 0, 1, 1)慢启动快结束easeOut(0, 0, 0.58, 1)快启动慢结束easeInOut(0.42, 0, 0.58, 1)首尾都慢源码用as const声明所有控制点为字面量类型可安全地直接赋值给BezierCurve。自定义曲线直接书写 CSS cubic-bezier 控制点当内置预设不够用时可以像写 CSScubic-bezier(x1, y1, x2, y2)一样定义任意曲线。注意 CSS 语法允许 y 轴控制点超出[0,1]以产生回弹效果tween同样支持let customCurve { x1: 0.68, y1: -0.55, x2: 0.265, y2: 1.55, } let animation tween({ from: 0, to: 100, duration: 500, curve: customCurve, })从类型定义看BezierCurve 仅约束四个控制点字段x1/x2通常落在0~1时间轴而y1/y2可以越界数值轴这为“带轻微回弹”的缓动效果留出了空间。在组件中使用用handle.signal自动清理tween属于命令式动画在 Remix UI 组件中运行requestAnimationFrame循环时必须处理组件销毁后的清理。文档给出的模式是在每一帧tick开始时检查handle.signal.aborted一旦组件卸载立即停止避免对已卸载 DOM 的无效写入function AnimatedValue(handle: Handle) { let value 0 function animateTo(target: number) { let animation tween({ from: value, to: target, duration: 300, curve: easings.easeOut, }) animation.next() // Initialize function tick(timestamp: number) { if (handle.signal.aborted) return let result animation.next(timestamp) value result.value handle.update() if (!result.done) { requestAnimationFrame(tick) } } requestAnimationFrame(tick) } return () ( div div style{{ transform: translateX(${value}px) }}Moving/div button mix{[ on(click, () { animateTo(200) }), ]} Animate /button /div ) }要点拆解组件每次点击按钮都会从当前value起做 300ms 的easeOut补间handle.update()触发一次 Remix UI 重渲染handle.signal是 Remix UI 提供给组件处理器的中止信号AbortSignaltick内首行检查aborted即可在卸载时立即终止动画循环通过mix与on(click, ...)绑定事件是 Remix UI 组件原生的声明式事件写法。多属性动画多个 tween 并行驱动tween只负责单个数值的插值组合多个属性时创建多个生成器、在同一个requestAnimationFrame回调里并行推进即可let xAnimation tween({ from: 0, to: 100, duration: 500, curve: easings.easeOut }) let yAnimation tween({ from: 0, to: 50, duration: 500, curve: easings.easeOut }) let scaleAnimation tween({ from: 1, to: 1.5, duration: 500, curve: easings.easeOut }) xAnimation.next() yAnimation.next() scaleAnimation.next() function animate(timestamp: number) { let x xAnimation.next(timestamp) let y yAnimation.next(timestamp) let scale scaleAnimation.next(timestamp) element.style.transform translate(${x.value}px, ${y.value}px) scale(${scale.value}) if (!x.done || !y.done || !scale.done) { requestAnimationFrame(animate) } } requestAnimationFrame(animate)由于三个 tween 共享同一duration与曲线且都以首个时间戳为各自起点多值动画天然同步循环终止条件需要同时检查所有生成器的done。若希望每个属性采用不同的时长或缓动曲线只需在创建时各自指定即可仍可在同一回调中并行推进。同样的并行思路也出现在 animation/README.md 的示例里。API 参考tween(options)创建一个随时间在数值间插值的生成器。完整选项类型TweenOptionsinterface TweenOptions { from: number // Starting value to: number // Ending value duration: number // Duration in milliseconds curve: BezierCurve // Easing curve } interface BezierCurve { x1: number // First control point X (0-1) y1: number // First control point Y x2: number // Second control point X (0-1) y2: number // Second control point Y }返回类型Generatornumber, number, number——yield当前插值动画结束时return最终值即tonext()的返回值中done: true表示动画完成。duration单位为毫秒首次收到时间戳后开始计时。easings包含预设贝塞尔曲线的对象即上文的五个预设。何时使用tween何时改用其他方案tween适合以下场景原文 When to Use 归纳由requestAnimationFrame驱动的命令式动画Canvas/WebGL 动画DOM 之外没有 CSS transition 可用动画非 CSS 属性如数值状态、图表数据、滚动位置等复杂的有序动画序列多个阶段串联时逐帧控制进度。而对于大多数 UI 动画文档明确建议优先使用动画 mixinanimateEntrance、animateExit、animateLayout或配合 Spring API 的 CSS transition——详见 animation 模块总览 与 Spring API 文档。二者定位差异清晰tween是时间驱动的贝塞尔补间严格按时长执行、不会过冲spring是物理驱动的弹簧动画基于duration bounce参数生成 CSSlinear()缓动并可迭代出带过冲的进度序列。选择原则可概括为能用 CSS transition 表达就用spring/mixin需要逐帧掌控数值变化尤其 Canvas、非 CSS 属性、序列动画就用tween。延伸阅读Spring API 文档物理弹簧动画可字符串化为 CSS transition、展开为 WAAPI 参数或迭代为 0~1 进度animation 模块 READMEentrance/exit/layout/spring/tween 全套原语总览tween 源码实现贝塞尔求解与生成器完整实现animation 导出入口tween、easings及类型TweenOptions、BezierCurve的统一出口【免费下载链接】remixThe fully-stacked web framework项目地址: https://gitcode.com/GitHub_Trending/re/remix创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表