繁体   English   中英

反应从 URL 内联导入 SVG

[英]React Import SVG inline from URL

我正在解决需要将 SVG 图像从 URL(AWS S3)加载到反应组件的问题。 我能够使用本地文件中的 SVG 内联反应组件成功显示和加载图像。 但是,svg 文件需要从 S3 存储桶内联加载,JS svg 导入不适用于 URL。

所以我正在尝试为此找到最佳替代解决方案?

您应该获取svg图像并将其粘贴到html中

const SVG_URL = url = 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/106114/tiger.svg';

class Svg extends React.Component {
  state = {
    svg: null,
    loading: false,
  }

  componentDidMount() {
    fetch(this.props.url)
      .then(res => res.text())
      .then(text => this.setState({ svg: text }));
  }

  render() {
    const { loading, svg } = this.state;
    if (loading) {
      return <div className="spinner"/>;
    } else if(!svg) {
      return <div className="error"/>
    }
    return <div dangerouslySetInnerHTML={{ __html: this.state.svg}}/>;
  }
}

ReactDOM.render(
  <Svg url='https://s3-us-west-2.amazonaws.com/s.cdpn.io/106114/tiger.svg' />,
  document.querySelector("#app")
);

您可以在此处编辑示例https://jsfiddle.net/anu6x3bk/

React不建议使用dangerouslySetInnerHTML因此您应该使用svg-inline-react这样的包

@ivnkld的回答将我指向了正确的方向,谢谢! 对于像我这样的Google员工,这是带有钩子的相同方法的实现:

import React, { useEffect, useState } from 'react';

const SvgInline = props => {
    const [svg, setSvg] = useState(null);
    const [isLoaded, setIsLoaded] = useState(false);
    const [isErrored, setIsErrored] = useState(false);

    useEffect(() => {
        fetch(props.url)
            .then(res => res.text())
            .then(setSvg)
            .catch(setIsErrored)
            .then(() => setIsLoaded(true))
    }, [props.url]);

    return (
        <div 
            className={`svgInline svgInline--${isLoaded ? 'loaded' : 'loading'} ${isErrored ? 'svgInline--errored' : ''}`}
            dangerouslySetInnerHTML={{ __html: svg }}
        />
    );
}

对于那些想要避免使用危险的SetInnerHTML 的人,请查看以下示例。 一旦我们从 api 获取 svg 作为文本,我们将使用DOMParser将文本转换为Document对象。 然后我们将使用React.createElement来渲染图像(或)图标。

// utils/convertDocEleToReact.js
import { createElement } from "react";

const innerFunction = (element, props) => {
    const tagName = element.tagName;
    let _props = props || {};

    for(let i = 0; i < element.attributes.length; i++){
      _props[element.attributes[i].nodeName] = element.attributes[i].nodeValue;
    }

    let children = Array.from(element.children).map(item => innerFunction(item));

    return createElement(tagName, _props, children);
};

export const convertDocEleToReact = (element, props) => {
    try{
       return innerFunction(element, props);
    }
    catch(ex){
      return createElement("span", {}, "Error loading svg image");
    }
};
// components/SVGUrl.js
import React from "react";
import { convertDocEleToReact } from "./utils/convertDocEleToReact";

export const SVGUrl = ({ ...props }) => {
    const [ Comp, setComp ] = useState(null);
    const [loading, setLoading] = useState(false);

    useEffect(_ => {
        setLoading(true);
        fetch(/** svg url */)
          .then(res => res.text())
          .then(res => {
              const domParser = new DOMParser();
              const ele = domParser.parseFromString(res, "image/svg+xml");
              setComp(convertDocEleToReact(ele.documentElement, props));
              setLoading(false);
          });
    }, []);

    return loading ? "..." : Comp;
};

现在React支持SVG只需使用<img/>标签,如下所示。

<img src='https://s3-us-west-2.amazonaws.com/s.cdpn.io/106114/tiger.svg' />

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM