[前端]React中将svg地址渲染到界面上的两种方案

1、使用自带标签进行渲染
可以使用img、embed、picture、object等标签渲染,要注意地址的跨域,这种方法比较简单,但是没办法对拿到的svg进行操作,比如进行主题模式切换的同时切换svg颜色,由于svg中包含有fill-color等字段,设置style很难生效。当然,后端也可以返回两种不同主题的地址。

<img src={url}  />

<embed src={url} />

<picture>
	<source srcSet={url}></source>
</picture> 

<object
	data={url}
    style={{ width: '25px', height: '25px' }}
    type="image/svg+xml"
    />

2、获取svg地址内容,使用div的innerhtml进行渲染
可以先通过请求(fetch或者xmlrequest)获取到文件内容,但由于拿到的内容是字符串,不能直接当做节点渲染,所以可以使用div自带的输属性innerhtml进行渲染。这样做是因为SVG是XML格式的,可以直接作为HTML的一部分被渲染。
这样做的好处是可以对字符串进行一些修改,比如使用replace进行某些字段的匹配修改,但是对于不同的svg的格式要求可能相对严格,不适合封装为组件。
但是要注意这样的安全性,直接将不明字符串渲染到页面可能会导致XSS(跨站点脚本)攻击,所以要确保是安全的。

<div
	dangerouslySetInnerHTML={{
		 __html: svgString,
	}}
	></div> 

3、获取svg地址内容,转化为节点进行渲染
获取到内容之后,将字符串转为DOM元素,根据DOM元素丰富的属性可以很大程度上更改svg的颜色,但是要注意React不能直接渲染Html片段,需要转为React元素才能渲染,转换之后path可能wei空,所以需要特殊处理path的d属性

export const EuSvgUrlIcon: FC<EuUrlIconProps> = ({ url }) => {
  const [svg, setSvg] = useState<any>();
  const elementFromNode = (node: Node): JSX.Element | null => {
    if (node.nodeType === Node.ELEMENT_NODE) {
      const element = node as Element;
      const children = Array.from(element.childNodes || []).map(
        elementFromNode,
      );
      const attributes: any = {};
      Array.from(element.attributes).forEach((attr) => {
        attributes[attr.name] = attr.value;
      });
      // 特别处理<path>元素的情况,将d属性转换为children
      if (element.tagName.toLowerCase() === 'path') {
        const d = element.getAttribute('d');
        if (d) {
          children.push(React.createElement('path', { d }));
        }
      }
      return React.createElement(
        element.tagName.toLowerCase(),
        attributes,
        ...children,
      );
    } else if (node.nodeType === Node.TEXT_NODE) {
      return node.nodeValue
        ? React.createElement(React.Fragment, {}, node.nodeValue)
        : null;
    } else {
      return null;
    }
  };
  useEffect(() => {
  	//获取url内容的请求函数,
    url2svg(url).then((res) => {
      const svgNode = new DOMParser().parseFromString(
        res,
        'image/svg+xml',
      ).documentElement;
      const jsxSvg =
        svgNode && svgNode.nodeName === 'svg' ? elementFromNode(svgNode) : null;
      console.log(res, svgNode.nodeName, jsxSvg);
      setSvg(jsxSvg);
      //   setSvg(createElement(res || ''));
    });
    // new DOMParser().parseFromString(svg, 'image/svg+xml').documentElement
  }, [url]);
  return (
    <>
      {/* <div
        dangerouslySetInnerHTML={{
          __html: svg,
        }}
      ></div> */}
      {svg}
    </>
  );
};
  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值