元素动画

为单个DOM元素应用动画

过渡效果示例

如何使用各种过渡效果:

import { transition } from '@ssgoi/react';
import { fade, scale, blur, slide, fly, rotate, bounce } from '@ssgoi/react/transitions';

// Fade过渡
<div ref={transition({
  key: "fade-element",
  ...fade({ spring: { stiffness: 300, damping: 30 } })
})}>
  Fade效果
</div>

// Scale过渡
<div ref={transition({
  key: "scale-element",
  ...scale({ spring: { stiffness: 300, damping: 30 } })
})}>
  Scale效果
</div>

// Blur过渡
<div ref={transition({
  key: "blur-element",
  ...blur({ amount: 10, spring: { stiffness: 300, damping: 30 } })
})}>
  Blur效果
</div>

// Slide过渡(方向指定)
<div ref={transition({
  key: "slide-element",
  ...slide({ direction: 'left', spring: { stiffness: 300, damping: 30 } })
})}>
  Slide效果
</div>

// Fly过渡(自定义位置)
<div ref={transition({
  key: "fly-element",
  ...fly({ x: 200, y: -50, spring: { stiffness: 300, damping: 30 } })
})}>
  Fly效果
</div>

// Rotate过渡
<div ref={transition({
  key: "rotate-element",
  ...rotate({ spring: { stiffness: 300, damping: 30 } })
})}>
  Rotate效果
</div>

// Bounce过渡
<div ref={transition({
  key: "bounce-element",
  ...bounce({ spring: { stiffness: 300, damping: 30 } })
})}>
  Bounce效果
</div>

基本结构

TransitionConfig接口

interface TransitionConfig {
  spring?: {
    stiffness: number; // 弹簧刚度 (默认: 300)
    damping: number; // 阻尼系数 (默认: 30)
  };
  tick?: (progress: number) => void; // in: 0→1, out: 1→0
  prepare?: (element: HTMLElement) => void; // 动画开始前的初始设置
  onStart?: () => void;
  onEnd?: () => void;
}

过渡定义

interface Transition {
  in?: (element: HTMLElement) => TransitionConfig;
  out?: (element: HTMLElement) => TransitionConfig;
}

工作原理

  1. 挂载时: 当元素添加到DOM时执行in函数
  2. 卸载时: 在元素被移除前执行out函数
  3. 动画: 弹簧物理引擎生成进度
    • in: 0 → 1
    • out: 1 → 0
  4. tick回调: 每帧调用以更新样式

过渡预设

import { fade, scale /** etc */ } from "@ssgoi/react/transitions";

框架特定用法

import { transition } from "@ssgoi/react";

<div
  ref={transition({
    key: "unique-key",
    in: (element) => ({
      tick: (progress) => {
        element.style.opacity = progress;
        element.style.transform = `translateY(${20 * (1 - progress)}px)`;
      },
    }),
    out: (element) => ({
      tick: (progress) => {
        element.style.opacity = 1 - progress;
      },
    }),
  })}
>
  内容
</div>

进度行为

key

  • key必须在页面内唯一(这样即使DOM被创建后删除或删除后创建,动画状态也可以被跟踪)
  • 如果key未设置,则根据调用位置生成默认的自动键

in动画

  • progress: 0 → 1
  • 当元素出现时执行
  • 不透明度从0到1,从小尺寸到原始尺寸

out动画

  • progress: 1 → 0
  • 当元素消失时执行
  • 不透明度从1到0,从原始尺寸到小尺寸
// 示例:in和out的区别
{
  in: (element) => ({
    tick: (progress) => {
      // progress: 0 → 1
      element.style.opacity = progress;  // 0 → 1
    }
  }),
  out: (element) => ({
    tick: (progress) => {
      // progress: 1 → 0
      element.style.opacity = progress;  // 1 → 0
    }
  })
}

prepare回调

动画开始前准备DOM元素的阶段:

{
  in: {
    prepare: (element) => {
      // 在tick执行前设置初始状态
      element.style.willChange = 'opacity, transform';
    },
    tick: (progress) => ({
      opacity: progress,
      transform: `translateY(${20 * (1 - progress)}px)`
    })
  }
}