You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Anime.js实现SVG路径变形悬停动画未完成时无法反向播放的问题

解决SVG路径悬停动画中途反向失效的问题

我来帮你搞定这个SVG路径变形的动画问题!你遇到的核心问题是:每次鼠标悬停和移出时都新建了一个Anime.js动画实例,当正向动画还没跑完就触发反向时,两个动画会同时修改同一个<path>d属性,导致动画混乱、反向失效。

咱们用Anime.js的动画实例复用+reverse/play方法就能完美解决,思路是:

  • 提前定义好正向和反向的路径序列
  • 创建一个可控制的动画实例,手动管理播放/反向
  • 鼠标交互时,基于当前动画状态切换方向,而不是新建动画

修改后的完整代码

// 提前定义正向路径数组
const forwardPaths = [
  { value: 'm 4 100 h -4 v -100 h 0 z' },
  { value: 'm 38 100 h -38 v -100 h 0 z' },
  { value: 'm 38 100 h -38 v -100 h 50 z' },
  { value: 'm 87 100 h -87 v -100 h 50 z' },
  { value: 'm 87 100 h -87 v -100 h 128 z' },
  { value: 'M 175 100 h -175 v -100 h 125 Z' },
  { value: 'M 175 100 h -175 v -100 h 175 Z' },
];

// 直接反转正向数组得到反向路径,减少冗余
const reversePaths = forwardPaths.slice().reverse();

// 获取目标路径元素
const backPath = document.querySelector('#logo #back');

// 创建可复用的动画实例,关闭自动播放,手动控制
let pathAnimation = anime({
  targets: backPath,
  d: forwardPaths,
  easing: 'easeInOutQuart',
  duration: 500,
  autoplay: false,
  direction: 'normal'
});

// 绑定鼠标悬停/移出事件
$('#logo').hover(function() {
  // 如果当前是反向播放状态,先反转回正向
  if (pathAnimation.direction === 'reverse') {
    pathAnimation.reverse();
  }
  // 如果动画未开始或已完成,重置到起始位置
  if (!pathAnimation.began || pathAnimation.completed) {
    pathAnimation.seek(0);
  }
  // 播放正向动画
  pathAnimation.play();
}, function() {
  // 如果当前是正向播放状态,切换到反向
  if (pathAnimation.direction === 'normal') {
    pathAnimation.reverse();
  }
  // 播放反向动画
  pathAnimation.play();
});
body { background: #1d1e22 }
div { margin: 0 auto; width: 175px; margin-top: 10% }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js"></script>
<div>
<svg id="logo" data-name="logo" xmlns="http://www.w3.org/2000/svg" width="175" height="100" viewBox="0 0 175 100">
  <path id="back" d="m 4 100 h 0 v -100 h 0 z" fill="#ed1e79"/>
  <g id="frame">
    <polygon points="69.894 85.938 72.914 85.938 71.418 81.97 69.894 85.938" fill="#fff"/>
    <path d="M48.3137,81.535H46.8723v6.7521h1.4414c1.7847,0,3.7891-.73,3.7891-3.3624C52.1028,82.1278,50.0984,81.535,48.3137,81.535Z" fill="#fff"/>
    <path d="M92.0224,81.535H90.5809v6.7521h1.4415c1.7844,0,3.7887-.73,3.7887-3.3624C95.8111,82.1278,93.8068,81.535,92.0224,81.535Z" fill="#fff"/>
    <path d="M.0676.1441v100h175v-100ZM26.391,89.8027H24.6752V81.9622h-.0275l-2.9515,7.8405H20.4879l-2.91-7.8405H17.55v7.8405H15.9028V80.0472h2.7044l2.5261,6.9308h.0411l2.4986-6.9308h2.718Zm12.9452,0H32.6506V80.0472H39.089v1.5157H34.38v2.48h4.4616v1.46H34.38v2.756h4.9559Zm9.2522,0H45.1425V80.0472h3.4459c2.54,0,5.3677,1.2124,5.3677,4.8775C53.9561,88.3423,51.1281,89.8027,48.5884,89.8027Zm12.89,0h-1.73V80.0472h1.73Zm13.0138,0L73.5862,87.57H69.3715l-.8786,2.2325H66.5574l4.2281-9.7555h1.4964l4.187,9.7555Zm17.8047,0H88.8512V80.0472h3.4455c2.54,0,5.368,1.2124,5.368,4.8775C97.6647,88.3423,94.8367,89.8027,92.2967,89.8027Zm17.8457,0h-6.6853V80.0472h6.4382v1.5157h-4.7087v2.48h4.4616v1.46h-4.4616v2.756h4.9558Zm8.4153.2481a4.4231,4.4231,0,0,1-3.3364-1.3916l1.2357-1.1579a2.7642,2.7642,0,0,0,2.1279,1.0748c.81,0,1.7572-.3994,1.7572-1.4468,0-1.0195-1.0157-1.3085-2.2379-1.6949-1.18-.3721-2.4572-.9507-2.4572-2.7695,0-1.9839,1.7986-2.8657,3.5558-2.8657a4.2327,4.2327,0,0,1,2.8279,1.0474l-1.1257,1.24a2.3781,2.3781,0,0,0-1.7844-.84c-.7964,0-1.7164.3857-1.7164,1.3364,0,.8955.755,1.1572,1.8536,1.502,1.2493.3857,2.8415.937,2.8415,2.852C122.0993,89.0306,120.4657,90.0508,118.5577,90.0508Zm11.1191-.2481h-1.73V80.0472h1.73Zm14.7707-.51a8.2427,8.2427,0,0,1-3.6658.7579,5.1285,5.1285,0,1,1-.0408-10.2516,5.5509,5.5509,0,0,1,3.6923,1.226l-1.1943,1.2955a3.4448,3.4448,0,0,0-2.4844-.9922,3.5867,3.5867,0,0,0,.0822,7.1651,5.001,5.001,0,0,0,1.9358-.3448v-2.48h-2.0458V84.2357h3.7208Zm14.7849.51h-2.1966l-4.6129-7.5372h-.0272v7.5372h-1.73V80.0472h2.2928l4.5166,7.3028h.0272V80.0472h1.73ZM171.5,70.7715H3.6357V3.7254H171.5Z" fill="#fff"/>
  </g>
  <path id="lettern" d="M47.9876,18.2283V57.0422h-7.95L20.56,20.1657V55.9594h3.1232v1.0828h-7.78V55.9594h3.1231V18.2283H15.9028V17.1448H31.5761L46.4538,45.7574V18.2283H43.3307V17.1448h7.78v1.0835Z" fill="#fff"/>
  <path id="letterv" d="M90.577,46.7258l9.8813-28.4975H96.0289V17.1448h8.6884v1.0835h-2.6689L88.3623,57.6126h-4.77l-14.48-39.3843H66.5V17.1448H85.0687v1.0835H81.0371Z" fill="#fff"/>
  <path id="letterd" d="M159.2323,36.41q0,11.742-6.5871,16.3575-6.0771,4.2747-16.6958,4.2747H119.8788V55.9594h3.7484V18.2283h-3.7484V17.1448h17.5473q10.903,0,16.3543,4.4744T159.2323,36.41ZM134.7,55.9594h2.1584q5.735,0,8.2057-4.0751t2.47-13.6507V34.9279q0-12.8243-4.8837-15.4457a14.1046,14.1046,0,0,0-6.5871-1.2539H134.7Z" fill="#fff"/>
</svg>
</div>

关键改进点说明

  1. 复用动画实例:只创建一个Anime.js实例,彻底避免多动画同时修改元素属性的冲突问题
  2. 智能切换播放方向
    • 鼠标悬停时,自动判断当前动画状态,若处于反向播放则切换回正向,从当前进度继续播放
    • 鼠标移出时,同样基于当前状态切换到反向,保证平滑过渡
  3. 减少冗余代码:通过反转正向路径数组直接得到反向序列,不用手动重复编写反向路径

现在不管你什么时候移出鼠标,动画都会从当前状态平滑地反向过渡回去,不会再出现失效的情况啦!

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

火山引擎 最新活动