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

Posted

技术标签:

【中文标题】将 SVG 组件作为背景图像反应到 div【英文标题】:React SVG component as background-image to div 【发布时间】:2018-12-17 01:46:09 【问题描述】:

我正在尝试让 styled-components 获取作为反应组件的 SVG 并将其设置为背景图像,但出现错误:

TypeError:无法将符号值转换为字符串

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;

容器组件代码:

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);
`;

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

我也尝试过不使用样式化组件并使用内联样式但没有成功。

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

【问题讨论】:

【参考方案1】:

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

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

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

【讨论】:

【参考方案2】:

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

// MyComponent.js

import mySvg from './mySvg.svg';

...

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

... etc

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

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

【讨论】:

问题是关于创建一个 svg 作为反应组件,而不是从文件中加载一个普通的 svg【参考方案3】:
url(`data:image/svg+xml;utf8,$svgTxt`)

;或

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

就是这样。

【讨论】:

【参考方案4】:

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

这是更新后的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');
`;

这里是encodeSVG lib 文件:

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(/>\s1,</g, '><');
  data = data.replace(/\s2,/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(/ /g, '')
    .replace(/ /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")`;
;

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

【讨论】:

bg 变量在您的示例中未初始化。【参考方案5】:

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

你可以试试:

ReactDOMServer.renderToString(StepSVG)

ReactDOMServer.renderToStaticMarkup(StepSVG)

我还没有测试这是否真的有效,但我想你值得一试:)

【讨论】:

【参考方案6】:

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

换句话说:

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

在你的组件中:

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

当您导入这样的 SVG 文件时,create-react-app 会将包含生成的 URL 的 Webpack 加载器应用到您要导入的 SVG 中 - 可以将其传递给 background-image css 属性。

希望这会有所帮助!

【讨论】:

谢谢。这是我最初的方法,但我正在尝试动态渲染颜色。我想我只需要在这种方法中为每种颜色创建 N 个静态 SVG? 这是一种方法,但您仍然可以使用您原来的方法。在这种情况下,您必须使用 CSS 将 SVG 分层到您的内容下方(z-index 属性将对此有所帮助)。 谢谢克里斯,因为我的原始方法现在似乎不可能,我将选择这个作为已解决。感谢您的帮助。

以上是关于将 SVG 组件作为背景图像反应到 div的主要内容,如果未能解决你的问题,请参考以下文章

如何将 SVG 的填充颜色更改为背景图像? [复制]

php 将后缩略图作为背景图像添加到任何div

为啥我的 SVG 背景图像不起作用?

你可以为 svg“背景图像”制作动画吗?

如何将svg浮动到background-size:contains的背景图像

将 SVG 转换为 PNG,并将应用的图像作为 svg 元素的背景