【问题标题】:Turning an SVG string into an image in a React component将 SVG 字符串转换为 React 组件中的图像
【发布时间】:2017-12-07 14:35:10
【问题描述】:

我在 React 组件中有一个动态生成的 SVG 字符串。我想将此作为图像嵌入到组件中。目前,我正在使用以下内容:

class SomeComponent extends React.Component {
    render() {
        var image = '<svg xmlns="http://www.w3.org/2000/svg" version="1.2" baseProfile="tiny" width="47.4" height="40.65" viewBox="21 18.5 158 135.5"><path d="M25,50 l150,0 0,100 -150,0 z" stroke-width="4" stroke="black" fill="rgb(128,224,255)" fill-opacity="1" ></path><path d="M25,50 L175,150 M25,150 L175,50" stroke-width="4" stroke="black" fill="black" ></path><g transform="translate(0,0)" stroke-width="4" stroke="black" fill="none" ><circle cx="100" cy="30" r="7.5" fill="black" ></circle><circle cx="70" cy="30" r="7.5" fill="black" ></circle><circle cx="130" cy="30" r="7.5" fill="black" ></circle></g></svg>';
        return (
            <div dangerouslySetInnerHTML={{ __html: image }} />
        )
    }
}

但是,使用名为dangerouslySetInnerHTML 的属性让我很不安。有没有更普遍接受(和更安全)的方法来做到这一点?

【问题讨论】:

标签: javascript reactjs svg xss


【解决方案1】:

由于 SVG 是动态生成的,并且您不能将其存储为资产,因此作为 dangerouslySetInnerHTML 的替代方案,您可以简单地将其设置为图像上的 Data URI。所以像......


class SomeComponent extends React.Component {
    render() {
        const image = '<svg xmlns="http://www.w3.org/2000/svg" version="1.2" baseProfile="tiny" width="47.4" height="40.65" viewBox="21 18.5 158 135.5"><path d="M25,50 l150,0 0,100 -150,0 z" stroke-width="4" stroke="black" fill="rgb(128,224,255)" fill-opacity="1" ></path><path d="M25,50 L175,150 M25,150 L175,50" stroke-width="4" stroke="black" fill="black" ></path><g transform="translate(0,0)" stroke-width="4" stroke="black" fill="none" ><circle cx="100" cy="30" r="7.5" fill="black" ></circle><circle cx="70" cy="30" r="7.5" fill="black" ></circle><circle cx="130" cy="30" r="7.5" fill="black" ></circle></g></svg>';
        return (
            <div>
              <img src={`data:image/svg+xml;utf8,${image}`} />
            </div>
        )
    }
}

在此处查看帖子:https://css-tricks.com/lodge/svg/09-svg-data-uris/

【讨论】:

  • 如果您最终使用此方法,您可能需要将 SVG 输出包装在 encodeURIComponent() 中: &lt;img src={`data:image/svg+xml;utf8,${encodeURIComponent(image)}` /&gt;
  • 代码&lt;img src={`data:image/svg+xml;utf8,${image}` /&gt; 缺少} 以关闭src 属性
  • 这不适用于此 svg https://avatars.dicebear.com/api/jdenticon/:seed.svg 我也在 css-trick 中测试过
【解决方案2】:

您可以做的一件事是将您的 svg 字符串转换为 base64,然后像这样使用它:

const image = '<svg xmlns="http://www.w3.org/2000/svg" version="1.2" baseProfile="tiny" width="47.4" height="40.65" viewBox="21 18.5 158 135.5"><path d="M25,50 l150,0 0,100 -150,0 z" stroke-width="4" stroke="black" fill="rgb(128,224,255)" fill-opacity="1" ></path><path d="M25,50 L175,150 M25,150 L175,50" stroke-width="4" stroke="black" fill="black" ></path><g transform="translate(0,0)" stroke-width="4" stroke="black" fill="none" ><circle cx="100" cy="30" r="7.5" fill="black" ></circle><circle cx="70" cy="30" r="7.5" fill="black" ></circle><circle cx="130" cy="30" r="7.5" fill="black" ></circle></g></svg>';
const buff = new Buffer(image);
const base64data = buff.toString('base64');

return <img src='data:image/svg+xml;base64,${base64data }' alt="" />

如果你不想使用缓冲区,使用这个:

const base64data = btoa(unescape(encodeURIComponent(image)));

【讨论】:

  • 这适用于我的情况,而 &lt;img src={data:image/svg+xml;utf8,${encodeURIComponent(image)}` />` 不适用。我的 linter(@types/node)说 btoa 已被弃用。最好使用Buffer.from(unescape(encodeURIComponent(image)),"latin1").toString("base64");
  • 这里不需要latin1,尽管btoa()使用latin1而不是utf8
  • 这在我的情况下有效。非常感谢您
  • 完美!谢谢 :)
【解决方案3】:

只需使用这个包:https://github.com/gilbarbara/react-inlinesvg

例子:

import SVG from 'react-inlinesvg';

...    

const mySVG = '<svg xmlns="http://www.w3.org/2000/svg">...</svg>';
return <SVG src={mySVG} />;

【讨论】:

    【解决方案4】:

    React refinnerHTML 效果很好而且很干净。

    var image = '<svg xmlns="http://www.w3.org/2000/svg" version="1.2" baseProfile="tiny" width="47.4" height="40.65" viewBox="21 18.5 158 135.5"><path d="M25,50 l150,0 0,100 -150,0 z" stroke-width="4" stroke="black" fill="rgb(128,224,255)" fill-opacity="1" ></path><path d="M25,50 L175,150 M25,150 L175,50" stroke-width="4" stroke="black" fill="black" ></path><g transform="translate(0,0)" stroke-width="4" stroke="black" fill="none" ><circle cx="100" cy="30" r="7.5" fill="black" ></circle><circle cx="70" cy="30" r="7.5" fill="black" ></circle><circle cx="130" cy="30" r="7.5" fill="black" ></circle></g></svg>';
    
    
    const useApp = () => {
      const svgWrapperRef = React.useRef();
      React.useEffect(() => {
        svgWrapperRef.current.innerHTML = image;
      }, [])
      return {
        svgWrapperRef
      }
    }
    const App = () => {
      const {svgWrapperRef} = useApp()
      return (
        <div ref={svgWrapperRef}></div>
      )
    }
    
    const root = document.getElementById('root')
    
    ReactDOM.render(<App />, root)
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
    
    <div id="root"></div>

    祝你好运……

    【讨论】:

      【解决方案5】:

      我会将 svg 图片存储在单独的文件夹中(assets),然后将图片导入到 react 组件中

      类似这样的:

      SomeComponent.js:

      import { SampleImage } from '../assets/SomeFile';
      
      class SomeComponent extends React.Component {
          render() {
      
              return (
                  <div>
                    <img src={SampleImage} />
                  <div/>
              )
          }
      }
      

      SomeFile.svg:

      <?xmlns="http://www.w3.org/2000/svg" version="1.2"encoding="UTF-8"?>
      
       <svg baseProfile="tiny" width="47.4" height="40.65" viewBox="21 18.5 158 135.5"><path d="M25,50 l150,0 0,100 -150,0 z" stroke-width="4" stroke="black" fill="rgb(128,224,255)" fill-opacity="1" ></path><path d="M25,50 L175,150 M25,150 L175,50" stroke-width="4" stroke="black" fill="black" ></path><g transform="translate(0,0)" stroke-width="4" stroke="black" fill="none" ><circle cx="100" cy="30" r="7.5" fill="black" ></circle><circle cx="70" cy="30" r="7.5" fill="black" ></circle><circle cx="130" cy="30" r="7.5" fill="black" >
          </circle></g>
       </svg>
      

      【讨论】:

      • 这是使用 svgs 的正常方式。我有一个字符串,想从中生成一个元素。字符串来自服务器
      猜你喜欢
      • 1970-01-01
      • 2020-09-22
      • 2021-08-24
      • 2016-04-26
      • 1970-01-01
      • 2021-08-20
      • 1970-01-01
      • 2023-03-28
      相关资源
      最近更新 更多