在线示例:stackblitz-starters-xx1aeg.stackblitz.io

基础示例

将 SVG 标签转换为动画组件

  • Path: motion. Path
  • Circle : motion. Circle
  • Rect :motion. Rect

一个简单的 circle 动画

export const MyAnimatedCircle = () => {
  return (
    <svg width="100" height="100">
      <motion.circle
        cx="50"
        cy="50"
        r="40"
        fill="blue"
        animate={{ scale: [1, 1.5, 1] }}
        transition={{ duration: 2, loop: Infinity, ease: 'easeInOut' }}
      />
    </svg>
  );
}

基础的线条绘制动画

export const MyLineDrawing = () => {
  return (
    <svg width="200" height="200">
      <motion.path
        d="M10 10 L190 10"
        stroke="black"
        strokeWidth="2"
        strokeDasharray="0 1"
        animate={{ strokeDasharray: [0, 1], pathLength: [0, 1] }}
        transition={{ duration: 2, ease: 'easeInOut' }}
      />
    </svg>
  );
};

循环播放的 path 动画

export const MyAnimatedPath = () => {
  return (
    <svg width="200" height="200">
      <motion.path
        d="M20 20 L180 20 L180 180 L20 180 Z"
        fill="none"
        stroke="black"
        strokeWidth="2"
        animate={{ pathLength: [0, 1, 0] }}
        transition={{ repeat: Infinity, repeatType: 'reverse', duration: 2 }}
      />
    </svg>
  );
};

SVG 形状改变动画

export const MorphingPath = () => {
  return (
    <svg width="200" height="200">
      <motion.path
        d="M20 20 C50 20 50 150 150 150"
        fill="none"
        stroke="black"
        strokeWidth="2"
        animate={{ d: 'M20 20 C20 50 150 50 150 150' }}
        transition={{ duration: 2, repeat: Infinity, repeatType: 'reverse' }}
      />
    </svg>
  );
};

多个动画组

export const MyPulsingCircles = () => {
  return (
    <svg width="200" height="200">
      <motion.circle
        cx="50"
        cy="50"
        r="10"
        fill="green"
        variants={circleVariants}
        animate="pulse"
      />
      <motion.circle
        cx="150"
        cy="50"
        r="10"
        fill="green"
        variants={circleVariants}
        animate="pulse"
      />
      {/* You can add more circles here */}
    </svg>
  );
};

可交互的动画

Hover 时放大
点击是缩小

export const MyInteractiveSVG = () => {
  return (
    <svg width="200" height="200">
      <motion.rect
        x="50"
        y="50"
        width="100"
        height="50"
        fill="red"
        whileHover={{ scale: 1.1 }}
        whileTap={{ scale: 0.9 }}
      />
    </svg>
  );
};

通过状态和交互来控制动画

export const MyColorChangingGraphic = () => {
  const [color, setColor] = useState('#f00');
 
  return (
    <svg onClick={() => setColor(color === '#f00' ? '#00f' : '#f00')}>
      <motion.circle
        cx="100"
        cy="100"
        r="40"
        fill={color}
        initial={{ opacity: 0 }}
        animate={{ opacity: 1 }}
        whileTap={{ scale: 0.8 }}
      />
    </svg>
  );
};
 

SVG 动画的使用场景

  • 导航菜单:动画的 SVG 图标可以增强导航菜单,通过对用户交互做出反应,指示状态或可用操作的变化
  • 数据可视化:交互式的图表和图形在悬停时可以使数据更易于理解,当用户进行探索时,突出显示重要信息
  • 引导教程:逐步指南可以使用 SVG 动画来引导用户注意特定区域,提高复杂任务的学习曲线
  • 游戏元素:交互式动画可以将静态元素转换为可玩的特性,例如按钮可以通过愉快的动画做出响应

将交互式 SVG 动画融入页面可以将静态页面转换为动态和沉浸式的网络体验。可以创建既视觉吸引人又直观易用的界面

SVG 动画的性能优化

  • 简化 SVG 路径:使用创建形状所需的最少点数,复杂的路径可能会占用大量处理器资源
  • 避免大规模重绘:动画不会导致布局变化或重绘的属性,例如 opacitytransform
  • 使用硬件加速:应用 CSS 属性,如 transform: translate3d(0,0,0) 以启用硬件加速,实现更流畅的动画效果
  • 限制动画元素的数量:更多的元素需要更多的处理能力。对于你要进行动画的内容要有选择性
  • 利用 Framer Motion 的 animatePresencelayout 功能:这些功能可以在组件进入、退出或更改布局时进行动画处理,从而减少不必要的渲染

查看原文