指南 · 01

值与 style

在组件中持有一个值,用 calc() 推导输出,并选择 CSS 变量写入的位置。

持有一个值

useAnimatedValue(initial) 创建一个归组件所有的 Value。可以用数字,也可以用 { x: 0, opacity: 1 } 这样的记录,每个字段都是独立的值。

在普通的 style 中,Hook 的值是 var(--kkwa-…, initial) 这个标记。更新时会把变量写到使用它的元素上,React 不会渲染。

正在准备示例…

用 calc() 推导

无缓动的插值,以及与常数的 add、subtract、multiply 或 divide,都会变成同一个变量的精确 calc() 表达式。它们由浏览器推导,不会每帧运行 JavaScript。

Slide.jsx
const progress = useAnimatedValue(0);

// A linear interpolation of a hook value is a calc() of the same CSS variable.
const x = progress.interpolate({ inputRange: [0, 1], outputRange: ['0px', '180px'] });
const half = multiply(progress, 0.5);

<div style={{ opacity: half, transform: `translateX(${x})` }} />;

正在准备示例…

颜色与自定义计算

颜色、带缓动的插值、modulo、diffClamp 和 AnimatedComputed 无法写成 calc()。useAnimatedCSS(node) 为它们提供专属的 CSS 变量,由 JavaScript 更新,生命周期与组件一致。

直接在 style 中使用这样的节点会抛出异常,所以开销永远不会被隐藏。

Glow.jsx
const progress = useAnimatedValue(0);

// Colors and eased curves are not calc() expressions: give them their own CSS value.
const color = useAnimatedCSS(
  progress.interpolate({ inputRange: [0, 1], outputRange: ['#3d3bf3', '#22b8f0'] }),
);

<div style={{ background: color }} />;

让 Hook 管理动画配方

useAnimated(initial, factory, deps) 持有值,以及在工厂函数中同步声明的所有控制器。挂载时启动,依赖变化时重新开始,卸载时停止。

如需由事件驱动播放,传入 { autoStart: false },然后在返回的值上调用 start()、stop() 或 reset()。

Intro.jsx
const intro = useAnimated(
  { opacity: 0, y: 24 },
  (value) => {
    parallel([
      timing(value.opacity, { toValue: 1, duration: 400 }),
      spring(value.y, { toValue: 0, stiffness: 220, damping: 20 }),
    ]);
  },
  [],
);

<section style={{ opacity: intro.opacity, transform: `translateY(calc(${intro.y} * 1px))` }} />;

一次写入,作用于多个元素

默认情况下,每个在内联样式中使用该值的元素都会收到这个变量。使用 scope 时,变量只在容器上写入一次并由子元素继承——元素有数百个时这是正确的选择。

AnimatedProvider scope={ref} 为其下的所有 Hook 值设置默认 scope。

Field.jsx
const field = useRef(null);

// Written once on the field; every child that uses the value inherits it.
const wave = useAnimatedValue(0, { scope: field });

<div ref={field}>
  {items.map((item) => (
    <i key={item} style={{ transform: `rotate(calc(${wave} * 1turn))` }} />
  ))}
</div>;

在 JavaScript 中读取值

getValue() 返回快照,不会让 React 订阅。useAnimatedListener(node, fn) 在每次变化时调用你,并在卸载时移除监听器。适合 canvas 绘制或数据统计,不要用于渲染。

搜索

输入关键词搜索文档。