使用 JS 更改 SVG 的渐变

Changing SVG's gradient using JS

我试图通过更改 stop-color 属性来更改以下 SVG 元素中渐变的终止色,但它不起作用:

<svg><defs> 
<linearGradient gradientTransform="rotate(90)">
<stop offset="40%" stop-color="purple" id="firstGradient"/>
<stop offset="100%" stop-color="red" id="secondGradient"/>
</linearGradient>
</defs>
<Here's a long line of picture>
</svg>

我正在使用以下脚本语句来尝试更改停止颜色:

document.getElementById("firstGradient").stopColor ="red";

我也试过了document.getElementById("firstGradient").attr.stop-color = "red";.

这两种方法都不起作用。如何更改停止颜色?

你试过吗:

document.getElementById("firstGradient").style.stopColor ="red";

你犯的错误是假设——我不确定你使用什么资源作为参考——是在任何对象上定义了一个 stopColor 属性 document.getElementByid("firstGradient") returns。没有。

您称为“firstGradient”的元素是一个 SVGStopElement,正如您从规范中看到的那样,它不提供任何 stopColor 属性.

但无需担心 - 通过更改实际元素属性,您正在更改停止颜色,这就是文档对象模型的工作方式 - 您根本不需要使用元素的任何特殊属性来更改实际属性:

document.getElementById("firstGradient").setAttribute("stop-color", "red");

就是这样。 setAttribute 函数可用于任何文档元素、SVG、HTML 或任何其他 namespace/kind.

顺便说一句,我不会将停止色称为渐变——将您称为“firstGradient”的元素称为“firstGradient”只是一种误导——它是 停止色不是 gradient,渐变是实际的 linearGradient 元素。因此,如果要分配标识符,请分别将“gradientFirstStopColor”和“gradientSecondStopColor”分配给第一个和第二个 stop 元素(如果有的话)。

但是您也可以使用它们在子层次结构中的顺序来识别停止颜色元素:

document.querySelector("linearGradient > stop:nth-of-type(1)").setAttribute("stop-color", "red");

您可以使用其他 CSS 选择器或 API(例如 querySelectorAll("linearGradient > stop")[1]),我的观点是您不必绝对求助于分配标识符,尽管它在某些情况下有所帮助——它们绝对有其合法用途。

当然在停止元素上使用 style 属性 也可以,但我个人认为在非渲染元素上使用 style 的语义(不渲染渐变)他们自己)元素,是疯子——基本上是一个泄漏的抽象。

现在是 2022 年,我们有原生 JavaScript Web Components

将您的 <svg> 包装在 <svg-gradient> Onload 中,它将读取定义的 GRAD 颜色数组并 创建 <stop > <svg>

中的值

注意3处定义和使用GRAD;这允许在 <svg>

中使用多个渐变

<svg-gradient GRAD="red,red,red,red,red,red,#f8991d,#ffe400,#51ff00,#0066ae,#1b449c,#792b87">
  <svg viewBox="0 0 512 512">
    <defs>
      <linearGradient id="GRAD"></linearGradient>
    </defs>
    <circle r="255" cx="256" cy="256" fill="url(#GRAD)" />
  </svg>
</svg-gradient>


<script>
  customElements.define("svg-gradient", class extends HTMLElement {
    connectedCallback() {
      setTimeout(() => { // make sure innerHTML was parsed
        this.querySelectorAll("linearGradient")
          .forEach(gradient => {
            gradient.innerHTML =
              this
              .getAttribute(gradient.id)
              .split(",")
              .map((color, idx, colors) => 
                 `<stop offset="${idx*1/colors.length}" stop-color="${color}"/>`)
              .join("")
          });
      })
    }
  })
</script>