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

如何在JavaScript路径变形时保留SVG样式(颜色)?

问题描述

我正在开发一个动画地图,包含23个图标,用户滚动页面时,图标会从红白警报信号变形为对应颜色的对话气泡。变形动画运行正常,但SVG中指定的颜色无法在动画过程中同步生效。我需要红色警报图标在滚动时,颜色随变形进度逐渐过渡到对话气泡路径指定的橙色/蓝色等,变形完成时颜色也同步切换完成。


现有样式代码

.st0{fill:#FFCA19;stroke:#FFFFFF;stroke-miterlimit:10;}
.st1{fill:#FFFFFF;}
.st2{fill:#279CD7;}
.st3{fill:#E44D25;}
.st4{fill:#E1A6CA;}
.st5{fill:#F68C22;}
.st6{fill:#3B2F8F;}
.st7{fill:#70BE54;}

图标集示例(23个之一)

<g id="iconset1">
    <path id="bub1" d="M83.5 110.2c0-7.6-6.1-13.7-13.7-13.7s-13.7 6.1-13.7 13.7 6.1 13.7 13.7 13.7h.8l-1.5 3.7 9-6.4c3.3-2.5 5.4-6.5 5.4-11z" class="st2"/>
    <path id="altbg1" d="M76.7 118.1H62.9c-1.1 0-2-.6-2.6-1.5-.5-.9-.5-2 0-3l6.9-11.9c.5-.9 1.5-1.5 2.6-1.5s2 .6 2.6 1.5l6.9 11.9c.5.9.5 2 0 3-.6 1-1.6 1.5-2.6 1.5z" class="st1"/>
    <path id="alt1" d="m79.3 113.5-6.9-11.9c-.6-.9-1.5-1.5-2.6-1.5s-2.1.6-2.6 1.5l-6.9 11.9c-.5 1-.5 2.1 0 3 .6.9 1.5 1.5 2.6 1.5h13.8c1 0 2-.5 2.6-1.5.5-1 .5-2 0-3zm-7.9 1.8h-3.2v-2.9h3.2v2.9zm.1-9.4c0 1.4-.7 5.1-.7 5.5h-2c0-.3-.7-4.1-.7-5.4v-1.8h3.4v1.7z" class="st3"/>
  </g>

现有CSS代码

.container {
  position: absolute;
  margin-left: auto;
  margin-right: auto;
  left: 0;
  right: 0;
  div-align: center;
  height: 80%;
}

[id^="bub"] {
  visibility: hidden;
}

body {
  background-color: lightblue;
}

现有JS代码

let main_tl = []; 
let iconmorphComplete = []; 
let animationStarted = false;

function iconmorph(altSelector, bubSelector) {
  let tl = new TimelineMax();
  let s_tl = new TimelineMax();
  tl.to(altSelector, 3, {morphSVG: bubSelector}, "start");
  tl.eventCallback("onComplete", function() {
    iconmorphComplete[altSelector] = true;
  });
  return tl;
}

function handleScroll() {
  const scrollPercentage = (window.scrollY / (document.documentElement.scrollHeight - window.innerHeight)) * 100;

  if (scrollPercentage >= 0 && !animationStarted) {
    for (let i = 1; i <= 23; i++) {
      const altSelector = "#alt" + i;
      const bubSelector = "#bub" + i;
      main_tl[altSelector] = iconmorph(altSelector, bubSelector);
      animationStarted = true;
    }
  }

  if (animationStarted) {
    for (let i = 1; i <= 23; i++) {
      const altSelector = "#alt" + i;
      const progress = (scrollPercentage - 0) / (120 - 0); 
      if (!iconmorphComplete[altSelector]) {
        main_tl[altSelector].progress(progress).pause();
      }
    }
  }
}

window.addEventListener('scroll', handleScroll);

已尝试但无效的修改

尝试1

function iconmorph(altSelector, bubSelector) {
  let tl = new TimelineMax();
  let s_tl = new TimelineMax();
  
  tl.set(altSelector, { fill: 'currentColor' });
  tl.set(bubSelector, { fill: 'currentColor' });

  tl.to(altSelector, 3, { morphSVG: bubSelector }, "start");
  tl.eventCallback("onComplete", function() {
    iconmorphComplete[altSelector] = true;
  });
  
  return tl;
}

尝试2

function iconmorph(altSelector, bubSelector) {
  let tl = new TimelineMax();
  let s_tl = new TimelineMax();

  const altColor = $(altSelector).attr('fill');

  tl.set(altSelector, { fill: altColor });
  tl.set(bubSelector, { fill: 'currentColor' });

  tl.to(altSelector, 3, { morphSVG: bubSelector }, "start");
  tl.to(altSelector, 3, { fill: 'currentColor' }, "start");
  tl.to(bubSelector, 3, { fill: altColor }, "start");

  tl.eventCallback("onComplete", function() {
    iconmorphComplete[altSelector] = true;
  });

  return tl;
}

解决方案

问题核心是需正确获取目标气泡的实际填充色,同步执行颜色过渡与变形动画,同时规避CSS类与内联样式的优先级冲突。

修改iconmorph函数如下:

function iconmorph(altSelector, bubSelector) {
  let tl = new TimelineMax();
  // 获取警报图标的初始计算颜色(从CSS类提取,而非内联属性)
  const altEl = document.querySelector(altSelector);
  const altColor = getComputedStyle(altEl).fill;
  // 获取目标气泡的计算颜色
  const bubEl = document.querySelector(bubSelector);
  const bubColor = getComputedStyle(bubEl).fill;

  // 同步执行变形与颜色过渡动画
  tl.to(altSelector, 3, { 
    morphSVG: bubSelector,
    fill: bubColor // 随变形进度过渡到气泡颜色
  }, "start");

  tl.eventCallback("onComplete", function() {
    iconmorphComplete[altSelector] = true;
    // 动画完成后隐藏警报背景,显示气泡
    const iconIndex = altSelector.slice(-1);
    document.querySelector(`#altbg${iconIndex}`).style.visibility = 'hidden';
    bubEl.style.visibility = 'visible';
  });
  
  return tl;
}

同时调整气泡的CSS可见性设置,避免影响颜色获取:

[id^="bub"] {
  visibility: hidden;
  position: absolute; /* 防止布局偏移 */
}

关键说明

  1. 使用getComputedStyle获取元素实际渲染的颜色,而非直接读取fill属性,因为颜色由CSS类定义而非内联属性。
  2. 在同一个动画步骤中同时指定morphSVG和fill属性,确保变形与颜色过渡进度完全同步。
  3. 动画完成后切换元素可见性,保证最终显示目标气泡图标。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 22:05:16