You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Next.js中加载API中的SVG并以<svg/>形式使用以支持样式修改?

可行方案汇总

方案1:Fetch SVG内容后用dangerouslySetInnerHTML渲染

这是最直接的实现方式,通过fetch获取在线SVG的文本内容,将其直接插入DOM,让SVG成为当前文档的一部分,就能被外部样式控制。

import { useState, useEffect } from 'react';

const InlineSvg = ({ src, className }) => {
  const [svgContent, setSvgContent] = useState('');

  useEffect(() => {
    const loadSvg = async () => {
      try {
        const res = await fetch(src);
        const rawSvg = await res.text();
        // 可选:强制统一设置fill为currentColor(如果API返回的SVG未配置)
        const processedSvg = rawSvg.replace(/fill="[^"]*"/g, 'fill="currentColor"');
        setSvgContent(processedSvg);
      } catch (err) {
        console.error('SVG加载失败:', err);
      }
    };

    src && loadSvg();
  }, [src]);

  return (
    <div
      className={className}
      dangerouslySetInnerHTML={{ __html: svgContent }}
      style={{ display: 'inline-block', verticalAlign: 'middle' }}
    />
  );
};

// 使用示例
// <InlineSvg src="https://api.com/image.svg" className="text-green-500" />

方案2:用SVGR将在线SVG转为React组件

SVGR支持处理字符串形式的SVG内容,将其转换为标准React组件,更贴合React开发模式,还能自动处理SVG属性映射。

首先安装依赖:

npm install @svgr/core

实现组件:

import { useState, useEffect } from 'react';
import svgr from '@svgr/core';

const SvgIcon = ({ src, className }) => {
  const [IconComponent, setIconComponent] = useState(null);

  useEffect(() => {
    const transformSvg = async () => {
      try {
        const res = await fetch(src);
        const svgText = await res.text();
        // 将SVG文本转为React组件代码
        const componentCode = await svgr(svgText, {}, { componentName: 'Icon' });
        // 动态生成组件
        const Icon = new Function('React', `return ${componentCode}`)(React);
        setIconComponent(<Icon className={className} />);
      } catch (err) {
        console.error('SVG转换失败:', err);
      }
    };

    src && transformSvg();
  }, [src, className]);

  return IconComponent || <span className="inline-block w-6 h-6 bg-gray-200" />;
};

// 使用示例
// <SvgIcon src="https://api.com/image.svg" className="text-blue-600" />

方案3:使用成熟第三方库react-inlinesvg

该库封装了SVG加载、缓存、错误处理等逻辑,开箱即用,适合快速开发场景。

安装依赖:

npm install react-inlinesvg

使用方式:

import SVG from 'react-inlinesvg';

const MyComponent = () => (
  <SVG
    src="https://api.com/image.svg"
    className="text-purple-500"
    // 加载完成后可手动调整SVG属性
    onLoad={(svgElement) => {
      svgElement.setAttribute('fill', 'currentColor');
    }}
    // 加载失败时的降级内容
    fallback={<span>图标加载失败</span>}
  />
);

关键注意事项

1. 跨域问题解决

如果目标SVG API未配置CORS允许你的应用域名访问,fetch会报错。此时可以在Next.js中创建代理路由:

创建pages/api/proxy-svg.js:

export default async function handler(req, res) {
  const { url } = req.query;
  if (!url) return res.status(400).send('缺少SVG地址参数');

  try {
    const svgRes = await fetch(decodeURIComponent(url));
    const svgText = await svgRes.text();
    res.setHeader('Content-Type', 'image/svg+xml');
    res.send(svgText);
  } catch (err) {
    res.status(500).send('代理加载失败');
  }
}

组件中使用代理地址:

<InlineSvg src={`/api/proxy-svg?url=${encodeURIComponent('https://api.com/image.svg')}`} />

2. 安全风险

无论是用dangerouslySetInnerHTML还是动态生成组件,都要确保加载的SVG来自可信来源,避免XSS攻击(恶意SVG可能包含脚本)。

3. 性能优化

可以用SWR或React Query缓存SVG请求结果,避免重复加载:

import useSWR from 'swr';

const fetcher = (url) => fetch(url).then(res => res.text());

const CachedInlineSvg = ({ src, className }) => {
  const { data: svgContent, error } = useSWR(src, fetcher);

  if (error) return <span>加载失败</span>;
  if (!svgContent) return <span>加载中...</span>;

  return (
    <div className={className} dangerouslySetInnerHTML={{ __html: svgContent }} />
  );
};

内容的提问来源于stack exchange,提问作者Vasil Kostadinov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 23:45:29