React SVG component as background-image to div

痴心易碎 提交于 2019-12-05 14:40:00

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.

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-image css property.

Hope this helps!

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

Here is the updated StepBar component:

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 encodeSVG lib file:

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! :)

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

// 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.

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

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

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

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

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).

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 :)

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

;or

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

that's it.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!