You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用framer-motion为SVG Transform字符串添加动画?

解决Framer Motion动画SVG Transform字符串的问题

问题原因

  1. Transform属性未更新:Framer Motion的animate默认操作元素的CSS样式,但SVG <g> 元素的transform是HTML属性而非CSS属性,直接修改样式不会同步到元素属性,导致页面无变化。
  2. 无法补间字符串值:transform是复合字符串(如translate(0,0) rotate(0)),Framer Motion仅能对单个数值类型属性(如数字、单一单位值)做插值补间,无法解析复合字符串生成过渡帧,因此只会直接跳转到最终值。

解决方案

核心是将复合transform字符串拆解为单个变换参数(如x、y、rotate、scale),针对数值属性做动画后,手动构建transform属性赋值给SVG元素,或直接用motion.g组件自动处理。

步骤1:解析Transform字符串

编写解析函数,将transform字符串拆为单个数值参数(可根据实际变换类型扩展):

function parseTransform(transformStr: string) {
  const result = { x: 0, y: 0, rotate: 0, scale: 1 };
  
  // 解析translate
  const translateMatch = transformStr.match(/translate\(([^,]+),([^)]+)\)/);
  if (translateMatch) {
    result.x = parseFloat(translateMatch[1]);
    result.y = parseFloat(translateMatch[2]);
  }
  
  // 解析rotate
  const rotateMatch = transformStr.match(/rotate\(([^)]+)\)/);
  if (rotateMatch) {
    result.rotate = parseFloat(rotateMatch[1]);
  }
  
  // 解析scale
  const scaleMatch = transformStr.match(/scale\(([^)]+)\)/);
  if (scaleMatch) {
    result.scale = parseFloat(scaleMatch[1]);
  }
  
  return result;
}

步骤2:手动实现动画(使用animate函数)

基于解析后的数值属性补间,在update回调中手动构建transform字符串并赋值给元素:

import { type FC, useRef, useEffect } from "react"
import { animate } from "motion"

const MyComponent:FC<{initialTransform:string, finalTransform:string}> = 
    ({initialTransform, finalTransform}) => {
   const ref = useRef<SVGGElement>(null);
   const initialParsed = parseTransform(initialTransform);
   const finalParsed = parseTransform(finalTransform);

   useEffect(() => {
       if (!ref.current) return;
       
       animate(
           { ...initialParsed },
           finalParsed,
           {
               duration: 1.5,
               update: (values) => {
                   ref.current!.setAttribute(
                       "transform",
                       `translate(${values.x}, ${values.y}) rotate(${values.rotate}) scale(${values.scale})`
                   );
                   console.log({ transform: ref.current!.getAttribute("transform") });
               }
           }
       );
   }, [initialParsed, finalParsed]);

   return <g ref={ref} transform={initialTransform}>
       {/* 你的SVG内容 */}
   </g>
}

步骤3:简洁方案(使用motion.g)

直接用Framer Motion的motion.g组件,它会自动处理SVG的transform属性:

import { type FC } from "react"
import { motion } from "framer-motion"

const MyComponent:FC<{initialTransform:string, finalTransform:string}> = 
    ({initialTransform, finalTransform}) => {
   const initialParsed = parseTransform(initialTransform);
   const finalParsed = parseTransform(finalTransform);

   return <motion.g
       initial={{ 
           x: initialParsed.x, 
           y: initialParsed.y, 
           rotate: initialParsed.rotate,
           scale: initialParsed.scale
       }}
       animate={{ 
           x: finalParsed.x, 
           y: finalParsed.y, 
           rotate: finalParsed.rotate,
           scale: finalParsed.scale
       }}
       transition={{ duration: 1.5 }}
   >
       {/* 你的SVG内容 */}
   </motion.g>
}

注意事项

  • 若transform包含skew等其他变换类型,需扩展parseTransform函数解析对应参数。
  • 确保初始与最终transform包含相同类型的变换(如初始显式设置rotate(0),避免补间异常)。

内容的提问来源于stack exchange,提问作者Jthorpe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 05:36:17