【问题标题】:How can I change the color of an SVG's child dynamically via props?如何通过道具动态更改 SVG 子项的颜色?
【发布时间】:2019-11-11 14:20:05
【问题描述】:

我正在使用 ReactComponent 导入 SVG。下面是相关代码:

import { ReactComponent as SuccessSVG } from "success.svg";

function SuccessIcon() {
  return <SuccessSVG />;
}

这是 SVG 本身:

<svg viewBox="0 0 233.3 233.3">
  <circle class="circle" cx="116.65" cy="116.65" r="116.65" />
  <path
    class="ok"
    d="M97.28,167.38l-33.7-33.7a6.34,6.34,0,1,1,9-9l29.21,29.21,76-76a6.34,6.34,0,1,1,9,9l-80.48,80.48A6.34,6.34,0,0,1,97.28,167.38Z"
    transform="translate(-8.51 -6.01)"
  />
</svg>

我想通过道具动态更改circlepath 的颜色。显然是这样的:

function SuccessIcon({ circleColor, pathColor) {
  ...
  ...
}

我已经看过this question。我不想使用公认答案的解决方案。另一个答案更接近我的愿望,但我无法实现。

顺便说一句,我不想​​在我的组件中直接使用 SVG。

【问题讨论】:

    标签: reactjs svg


    【解决方案1】:

    您已经将SuccessSVG 提取到它自己的组件中。现在你只需要通过props 传递你想要动态的配置

    const SuccessSvg = ({ cx, cy }) => {
        return (
            <svg viewBox="0 0 233.3 233.3" >
                <circle class="circle" cx={cx} cy={cy} r="116.65" />
                <path
                    class="ok"
                    d="M97.28,167.38l-33.7-33.7a6.34,6.34,0,1,1,9-9l29.21,29.21,76-76a6.34,6.34,0,1,1,9,9l-80.48,80.48A6.34,6.34,0,0,1,97.28,167.38Z"
                    transform="translate(-8.51 -6.01)"
                />
            </svg>
        )
    }
    
    const Component = () =>{
        return(
            <SuccessSvg color='blue' />
        )
    }
    

    遗憾的是,您必须考虑权衡。通过将 svg 声明为独立组件,您可以编写更多代码并控制自定义。这样您就可以传递将深入应用到您的 jsx 结构中的道具

    const CustomSVG = ({ svgProps, circleProps }) =>{
        return(
            <svg {...svgProps}>
                <circle {...circleProps} />
            </svg>
        )
    }
    

    这就是为什么链接问题的 OP 将 svg 包装到一个组件中,以便他可以将自定义 className 注入到 svg 中。声明式组件很棒,但你会受到它们的 API 的限制。在您的情况下,我没有看到太多替代方案,要么将结构抽象为它自己的组件,要么使用嵌套选择器。

    【讨论】:

    • 感谢您的回答。正如我在最后一行中所说的“我不想在我的组件中直接使用 SVG”实际上我不想这样做,但我想在这种情况下这是没有意义的,对吧?因为如果我这样做,那么我不需要将其导入为ReactComponent。我很好奇,没有别的办法吗?
    • svg 必须在某处实现。这是一个权衡,如果您将 svg 定义为独立组件,您将编写更多代码但可以控制它的实现。如果您使用的是不支持自定义的预定义 svg,那么遗憾的是您将无法更改它。 success.svg 来自哪里?是反应组件吗?
    • 不,直接来自 SVG 文件。所以,是的,你在某处实施它是对的。我只是想单独保留 SVG 文件并定义相关组件,使用ReactComponent 导入它们。对&lt;svg&gt; 使用 SVG 属性(例如 fillopacity 等)本身不是问题,它可以按我的预期工作,但我找不到设置子元素样式的方法。
    • 不是直接导入svg,难道你不能把它变成一个接受任意参数并返回对应的jsx的函数吗?
    • 是的,我不想在css 文件中写下所有可能的css 变体:) 我的愿望很简单,对于circle,我会传递一个颜色,对于@ 987654340@ 我将传递一种不同的颜色,它应该可以工作:) 正如我在问题中所说,另一个问题有不同的答案,但我无法使其工作。
    【解决方案2】:

    如果您不想像@Dupocas 建议的那样使用组件,您唯一的方法 就是为您的SVG 设置样式:

    // Example of CSS-in-JS , can be achieved with simple className.
    const SVGContainer = styled.div`
      svg {
        path {
          fill: ${({ circleColor }) => circleColor};
        }
      }
    `;
    
    function SuccessIcon({ circleColor }) {
      return (
        <SVGContainer circleColor={circleColor}>
          <SuccessSVG />
        </SVGContainer>
      );
    }
    
    const App = () => {
      return <SuccessIcon circleColor="palevioletred" />;
    };
    

    【讨论】:

    • 感谢您的回答。如果不使用styled-components,我怎么能做到这一点?用纯 CSS 样式?我正在使用 css-modulesclassnames 库,但纯 CSS 也可以。
    • 不知道怎么用纯css实现变量。
    • 但这是一个有效的答案,您只需要弄清楚如何将变量与纯 css 一起使用
    • 这是问我问题的原因 :) 我找不到使用纯 CSSReact 方式的方法。也许我应该提到我看到了styled-components 替代方案。我想我们可以这样做,因为它在这里提供了一个包装器组件,我们可以注入 CSS 道具。不过,感谢您的努力。
    【解决方案3】:

    我还没有找到解决这个问题的好方法。但我发现了这个:

    https://www.w3.org/TR/SVGParamPrimer/ :有了这个,我们可以编写一个 webpack-loader,将 svg 作为 data-url 包装在 object 元素的 data 属性中,这样我们就可以传递 props。我们可以从 svg 文件中使用的 props 类型来检测它。当然,我们需要用这种语法编写我们的 svg:&lt;rect fill="param(color) blue" stroke="param(outline) navy" /&gt;

    https://tabatkins.github.io/specs/svg-params/:这不是官方的,不知道会不会实现。

    由于解决方案需要以该语法编写 svg,因此可能与将 svg 代码复制到 jsx 文件并进行一些小改动没有区别。

    我有另一个想法:

    import SvgCar from './car.svg';
    const vdom = <SvgCar>
      <replace
        // path="a relative path point to an element or a property"
        path="children[2].fill"
        to={'red'} />
    </SvgCar>;
    
    // or
    const vdom2 = <SvgCar>{vdom => {vdom.children[2].fill="red";}}</SvgCar>
    

    但我认为这种方式会引入很多耦合。这不是一个好主意。

    【讨论】:

      猜你喜欢
      • 2022-01-09
      • 1970-01-01
      • 1970-01-01
      • 2015-11-08
      • 1970-01-01
      • 2013-10-28
      • 2020-01-01
      • 1970-01-01
      • 2018-04-06
      相关资源
      最近更新 更多