SSGOI

缩放动画

通过调整元素大小来创建放大/缩小效果

缩放动画

缩放(Scale)动画通过改变元素的大小来创建放大或缩小的效果。在提高注意力或表现视觉层次时非常有效。

基本用法

import { transition } from '@ssgoi/react';
import { scale } from '@ssgoi/react/transitions';

function Component() {
  const [isVisible, setIsVisible] = useState(true);
  
  return (
    <div>
      {isVisible && (
        <div ref={transition({ key: 'scale-element', ...scale() })}>
          应用了缩放动画的元素
        </div>
      )}
    </div>
  );
}

选项

interface ScaleOptions {
  start?: number;      // 起始大小比例(默认:0)
  opacity?: number;    // 起始透明度(默认:0)
  axis?: 'x' | 'y' | 'both';  // 缩放方向(默认:'both')
  spring?: {
    stiffness?: number;  // 弹簧刚度(默认:300)
    damping?: number;    // 阻尼系数(默认:30)
  };
}

选项说明

  • start: 动画开始时的大小(0 = 0%,1 = 100%)
  • opacity: 起始透明度(0-1)
  • axis: 缩放应用的轴
    • 'both': X轴和Y轴同时(默认)
    • 'x': 仅水平方向
    • 'y': 仅垂直方向
  • spring: 弹簧物理设置

使用示例

轴向缩放

X轴缩放(水平扩展)

const scaleX = scale({
  axis: 'x',
  spring: { stiffness: 400, damping: 35 }
});

<div ref={transition({ key: 'scale-x', ...scaleX })}>
  仅水平扩展的元素
</div>

Y轴缩放(垂直扩展)

const scaleY = scale({
  axis: 'y',
  spring: { stiffness: 400, damping: 35 }
});

<div ref={transition({ key: 'scale-y', ...scaleY })}>
  仅垂直扩展的元素
</div>

部分缩放

从较小尺寸开始的效果:

const partialScale = scale({
  start: 0.5,     // 从50%大小开始
  opacity: 0.3,   // 从30%透明度开始
});

<div ref={transition({ key: 'partial-scale', ...partialScale })}>
  从一半大小开始的元素
</div>

带弹跳效果的缩放

通过弹簧设置添加弹跳效果:

const bounceScale = scale({
  spring: { 
    stiffness: 200,  // 较低刚度产生弹跳
    damping: 15      // 较低阻尼增加振动
  }
});

<div ref={transition({ key: 'bounce-scale', ...bounceScale })}>
  弹跳缩放效果
</div>

实用示例

卡片悬停效果

function Card() {
  const [isHovered, setIsHovered] = useState(false);
  
  return (
    <div
      onMouseEnter={() => setIsHovered(true)}
      onMouseLeave={() => setIsHovered(false)}
    >
      {isHovered && (
        <div 
          ref={transition({ 
            key: 'card-hover', 
            ...scale({ start: 0.95, opacity: 0.8 }) 
          })}
          className="absolute inset-0 bg-blue-500/20 rounded-lg"
        />
      )}
      <div className="p-4">卡片内容</div>
    </div>
  );
}

模态框出现效果

function Modal({ isOpen, onClose }) {
  return (
    <>
      {isOpen && (
        <div className="fixed inset-0 flex items-center justify-center">
          <div 
            ref={transition({ 
              key: 'modal', 
              ...scale({ start: 0.8, opacity: 0 }) 
            })}
            className="bg-white rounded-lg p-6 shadow-xl"
          >
            <h2>模态框标题</h2>
            <p>模态框内容</p>
            <button onClick={onClose}>关闭</button>
          </div>
        </div>
      )}
    </>
  );
}

图标动画

function AnimatedIcon() {
  const [isActive, setIsActive] = useState(false);
  
  return (
    <button onClick={() => setIsActive(!isActive)}>
      {isActive ? (
        <HeartFilledIcon 
          ref={transition({ 
            key: 'heart-icon', 
            ...scale({ start: 0, spring: { stiffness: 600, damping: 20 } }) 
          })} 
        />
      ) : (
        <HeartOutlineIcon />
      )}
    </button>
  );
}

性能优化

  • transform: scale()使用GPU加速,性能优秀
  • 不会引起布局变化,避免重排
  • 即使同时应用于多个元素也能保持流畅的动画

性能提示

// 好的做法:使用transform
const goodScale = scale(); // 使用transform: scale()

// 避免的做法:直接修改width/height
const badScale = {
  in: (element) => ({
    tick: (progress) => {
      // 触发重排!
      element.style.width = `${progress * 100}px`;
      element.style.height = `${progress * 100}px`;
    }
  })
};

无障碍考虑

<button
  ref={transition({ 
    key: 'accessible-button', 
    ...scale({ start: 0.9 }) 
  })}
  aria-label="会放大的按钮"
  className="focus:outline-none focus:ring-2"
>
  点击我
</button>

推荐使用场景

  • 按钮/图标:点击反馈或悬停效果
  • 卡片/磁贴:选中状态或焦点显示
  • 模态框/弹出框:出现和消失动画
  • 图片画廊:缩略图放大效果
  • 图表/图形:数据可视化元素的强调