javascript 将 SVG 组件作为背景图像反应到 div

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/51244463/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 09:27:51  来源:igfitidea点击:

React SVG component as background-image to div

javascriptreactjssvgstyled-components

提问by user8467470

I am trying to get styled-components to take an SVG that is a react component and set it as a background-image but I get the error:

我试图让样式组件采用作为反应组件的 SVG 并将其设置为背景图像,但出现错误:

TypeError: Cannot convert a Symbol value to a string

类型错误:无法将符号值转换为字符串

SVG component code:

SVG 组件代码:

import React from "react";

const testSVG = props => {
  return (
    <svg version="1.1" id="Layer_1" x="0px" y="0px" viewBox="0 0 193.3 129.7">
      <g>
        <g>
          <g>
            <path
              fill="#434343"
              class="st0"
              d="M162.4,116c-4.6,7.5-15.6,13.6-24.4,13.6H16c-8.8,0-12.3-6.2-7.7-13.7c0,0,4.6-7.7,11.1-18.4
                c4.4-7.4,8.9-14.7,13.3-22.1c1.1-1.8,6.1-7.7,6.1-10.1c0-7.3-15-24.9-18.5-30.7C13.5,23.6,8.3,14.9,8.3,14.9
                C3.7,7.4,7.2,1.2,16,1.2c0,0,65.9,0,106.8,0c10,0,25.9-4.5,33.5,3.8c8.7,9.3,15.5,25.4,22.5,36.8c2.6,4.2,14.5,18.3,14.5,23.8
                c-0.1,7.6-16,26.1-19.6,32C167.1,108.3,162.4,116,162.4,116z"
            />
          </g>
        </g>
      </g>
    </svg>
  );
};

export default testSVG;

Container component code:

容器组件代码:

import React, { Component } from "react";
import StepSVG from "../../components/UI/SVGs/Test";

class StepBar extends Component {
  render() {
    const { steps } = this.props;

    return (
      <div>
        {steps
          ? steps.map(step => {
              return (
                <Wrap key={step._id} bg={StepSVG}>
                  <P>
                    {" "}
                    <Link to={"/step/" + step._id}>{step.title} </Link>
                  </P>
                </Wrap>
              );
            })
          : null}
      </div>
    );
  }
}

export default StepBar;

const Wrap = styled.div`
  padding: 30px 30px 0 0;
  display: inline-block;
  background-image: url(${props => props.bg});
`;

I am using create-react-app out of the box.

我正在使用开箱即用的 create-react-app。

I also tried without using styled components and used inline styles in place to no success.

我也尝试过不使用样式组件并在适当的位置使用内联样式但没有成功。

Is it possible to use an SVG as a background-image in this context with the SVG being a component?

在这种情况下,是否可以将 SVG 用作背景图像,而 SVG 是一个组件?

采纳答案by Kris Selbekk

Unfortunately, what you're trying to achieve is not possible. You'll have to keep your SVG as an actual .svg file (and link to that), or do some CSS trickery to place SVG component behind your foreground-component.

不幸的是,您想要实现的目标是不可能的。您必须将 SVG 保留为实际的 .svg 文件(并链接到该文件),或者执行一些 CSS 技巧将 SVG 组件放置在前景组件后面。

In other words:

换句话说:

<!-- step.svg -->
<svg version="1.1" id="Layer_1" x="0px" y="0px" viewBox="0 0 193.3 129.7">
  <!-- copy paste your svg here -->
</svg>

And in your component:

在您的组件中:

import stepSvgUrl from "../../components/UI/SVGs/step.
// ...
<Wrap key={step._id} bg={stepSvgUrl}>

When you import an SVG file like that, create-react-app applies a Webpack loader that includes the generated URL to the SVG you're importing - which is fine to pass into the background-imagecss property.

当您导入这样的 SVG 文件时,create-react-app 会应用一个 Webpack 加载器,其中包含您正在导入的 SVG 的生成 URL - 这很好地传递到background-imagecss 属性。

Hope this helps!

希望这可以帮助!

回答by Jordan Rolph

For React SVG background images, I find this works best:

对于 React SVG 背景图像,我发现这最有效:

// MyComponent.js

import mySvg from './mySvg.svg';

...

function MyComponent() {
  return (
    <div
       className="someClassName"
       style={{ backgroundImage: `url(${mySvg})` }}
    > 

... etc

The path to the SVG file will change when webpack bundles, so by using the template string you can keep things linked up.

当 webpack 打包时,SVG 文件的路径会改变,所以通过使用模板字符串,你可以保持链接。

In the CSS class you can do whatever styling you like.

在 CSS 类中,您可以做任何您喜欢的样式。

回答by phun-ky

Actually, there is a way to achieve what you want, without the SVG beeing a component:

实际上,有一种方法可以实现您想要的,而无需 SVG 成为组件:

Here is the updated StepBarcomponent:

这是更新的StepBar组件:

import React, { Component } from "react";
import StepSVG from "../../components/UI/SVGs/test.svg";
import encodeSVG from '../../lib/encodeSVG';

class StepBar extends Component {
  render() {
    const { steps } = this.props;

    return (
      <div>
        {steps
          ? steps.map(step => {
              return (
                <Wrap key={step._id} bg={StepSVG}>
                  <P>
                    {" "}
                    <Link to={"/step/" + step._id}>{step.title} </Link>
                  </P>
                </Wrap>
              );
            })
          : null}
      </div>
    );
  }
}

export default StepBar;

const Wrap = styled.div`
  padding: 30px 30px 0 0;
  display: inline-block;
  background-image: ${encodeSVG(bg, '#FF9900')};
`;

Here is encodeSVGlib file:

这是encodeSVGlib文件:

var symbols = /[\r\n"%#()<>?\[\\]^`{|}]/g;

function addNameSpace(data) {
  if (data.indexOf('http://www.w3.org/2000/svg') < 0) {
    data = data.replace(/<svg/g, "<svg xmlns='http://www.w3.org/2000/svg'");
  }

  return data;
}

function encodeSVG(data) {
  // Use single quotes instead of double to avoid encoding.
  if (data.indexOf('"') >= 0) {
    data = data.replace(/"/g, "'");
  }

  data = data.replace(/>\s{1,}</g, '><');
  data = data.replace(/\s{2,}/g, ' ');

  return data.replace(symbols, encodeURIComponent);
}

var encode = function(svg, fill) {
  if (fill) {
    svg = svg.replace(/<svg/g, `<svg fill="${fill}"`);
  }
  var namespaced = addNameSpace(svg);
  var dimensionsRemoved = namespaced
    .replace(/height="\w*" /g, '')
    .replace(/width="\w*" /g, '')
    .replace(/height='\w*' /g, '')
    .replace(/width='\w*' /g, '');
  var encoded = encodeSVG(dimensionsRemoved);

  var header = 'data:image/svg+xml,';
  var dataUrl = header + encoded;  

  return `url("${dataUrl}")`;
};

You import the svg, and use a string loader for svgs with your preferred build system (for example WebPack), pass that svg to encodeSVG, et voila! :)

您导入 svg,并使用您首选的构建系统(例如 WebPack)为 svgs 使用字符串加载器,将该 svg 传递给 encodeSVG,等等!:)

回答by user11011301

url(`data:image/svg+xml;utf8,${svgTxt}`)

;or

;或者

url(`data:image/svg+xml;base64,${btoa(svgTxt)}`)

that's it.

而已。

回答by paul.ago

I ended up using user11011301's solution in combination with raw-loaderto load the SVG content. Not the cleanest solution I'm sure, but I couldn't get it to work with other webpack loaders.

我最终将 user11011301 的解决方案与raw-loader结合使用来加载 SVG 内容。我确定这不是最干净的解决方案,但我无法让它与其他 webpack 加载器一起使用。

import searchIcon from '../../images/search.svg';

<input style={{backgroundImage: `url(data:image/svg+xml;base64,${btoa(searchIcon)})`}}/>

回答by Arber Sylejmani

You should probably convert it to string (as the error points out). Obviously you cannot use a React component as a background image because the react component is actually a javascript object (JSX converts to JS, then to HTML). So what you can do/try is use, ReactDOMServer (https://reactjs.org/docs/react-dom-server.html).

您可能应该将其转换为字符串(如错误所指出的那样)。显然你不能使用 React 组件作为背景图像,因为 React 组件实际上是一个 javascript 对象(JSX 转换为 JS,然后转换为 HTML)。所以你可以做/尝试的是使用 ReactDOMServer ( https://reactjs.org/docs/react-dom-server.html)。

You could try something with:

你可以尝试一些东西:

ReactDOMServer.renderToString(StepSVG)

or

或者

ReactDOMServer.renderToStaticMarkup(StepSVG)

I haven't tested if this actually works but worth a shot for you I guess :)

我还没有测试过这是否真的有效,但我猜对你来说值得一试:)