在 React 组件中将 SVG 字符串转换为图像

问题描述 投票:0回答:7

我在 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
7个回答
37
投票

由于 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/


13
投票

你可以做的一件事是将你的 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)));

7
投票

只需使用这个包: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} />;

5
投票

React ref
innerHTML
效果很好,很干净。

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>

祝你好运...


3
投票

就这样,我成功了

const svgStr = "<svg></svg>";
const svg = new Blob([svgStr], { type: "image/svg+xml" });
const url = URL.createObjectURL(svg);
<img src={url} />

0
投票

我知道问题是关于

string
对象的
svg
,但是你也可以直接使用
svg
对象

import React from 'react';

function CustomSvgObject({ }) {
    return <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>
}

您还可以更改

className
元素的
color
svg
,例如:

import React from 'react';

function CustomSvgObject({ className, color }) {
    return <svg className={className} 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={color} fill="rgb(128,224,255)" fill-opacity="1" ></path><path d="M25,50 L175,150 M25,150 L175,50" stroke-width="4" stroke={color} fill={color} ></path><g transform="translate(0,0)" stroke-width="4" stroke={color} fill="none" ><circle cx="100" cy="30" r="7.5" fill={color} ></circle><circle cx="70" cy="30" r="7.5" fill={color} ></circle><circle cx="130" cy="30" r="7.5" fill={color} ></circle></g></svg>
}

-3
投票

我会将 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>
© www.soinside.com 2019 - 2024. All rights reserved.