svg图标可以直接从icones.js一键获取某个图标库的所有图标,并且有多种格式可以下载。为了方便拓展这里我们使用json格式。因为拓展图标只需要将svg字符串加到我们的json文件内,所以你的图标库理论上可以非常非常丰富。
具体操作如下:

找到自己喜欢的图标库之后,点击右上角的菜单按钮
适用于React且支持渲染svg字符串的图标组件

然后点击json就会自动下载一个包含该图标库的json文件,里面带有改图标库的所有的图标的svg字符串。

适用于React且支持渲染svg字符串的图标组件

接下来完善我们的组件内容。这里我们用dangerouslySetInnerHTML这个API来实现。
因为dangerouslySetInnerHTML会直接插入html内容,所以我们可以加上DOMPurify来净化内容,此处我们暂不演示。
具体代码如下:

// SvgIcon.tsx
import React from "react";
import iconData from "@/assets/svgIcon.json";

interface IconProps extends React.HTMLAttributes<HTMLSpanElement> {
  name: keyof typeof iconData;
  size?: string;
}

const Icon: React.FC<IconProps> = ({
  name,
  size = "1rem",
  className = "",
  ...rest
}) => {
  const svg = iconData[name];

  if (!svg) {
    console.error(`Icon with name "${name}" not found.`);
    return null;
  }

  const modifiedSvgContent = svg
    .replace(/width="[^"]*"/, `width="${size}"`)
    .replace(/height="[^"]*"/, `height="${size}"`);

  return (
    <span
      className={`icon-${name} ${className}`}
      style={{ width: size, height: size }}
      dangerouslySetInnerHTML={{ __html: modifiedSvgContent }}
      aria-hidden="true"
      {...rest}
    />
  );
};

export default Icon;

这里我提供一些图标数据供使用:

// svgIcon.json
{
  "ri:github-fill": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"1em\" height=\"1em\" viewBox=\"0 0 24 24\"><path fill=\"currentColor\" d=\"M12.001 2c-5.525 0-10 4.475-10 10a9.994 9.994 0 0 0 6.837 9.488c.5.087.688-.213.688-.476c0-.237-.013-1.024-.013-1.862c-2.512.463-3.162-.612-3.362-1.175c-.113-.288-.6-1.175-1.025-1.413c-.35-.187-.85-.65-.013-.662c.788-.013 1.35.725 1.538 1.025c.9 1.512 2.337 1.087 2.912.825c.088-.65.35-1.087.638-1.337c-2.225-.25-4.55-1.113-4.55-4.938c0-1.088.387-1.987 1.025-2.687c-.1-.25-.45-1.275.1-2.65c0 0 .837-.263 2.75 1.024a9.28 9.28 0 0 1 2.5-.337c.85 0 1.7.112 2.5.337c1.913-1.3 2.75-1.024 2.75-1.024c.55 1.375.2 2.4.1 2.65c.637.7 1.025 1.587 1.025 2.687c0 3.838-2.337 4.688-4.562 4.938c.362.312.675.912.675 1.85c0 1.337-.013 2.412-.013 2.75c0 .262.188.574.688.474A10.016 10.016 0 0 0 22 12c0-5.525-4.475-10-10-10\"/></svg>",
  "my:gitee-fill": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"1em\" height=\"1em\" viewBox=\"0 0 24 24\"><path fill=\"currentColor\" d=\"M11.984 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12a12 12 0 0 0 12-12A12 12 0 0 0 12 0zm6.09 5.333c.328 0 .593.266.592.593v1.482a.594.594 0 0 1-.593.592H9.777c-.982 0-1.778.796-1.778 1.778v5.63c0 .327.266.592.593.592h5.63c.982 0 1.778-.796 1.778-1.778v-.296a.593.593 0 0 0-.592-.593h-4.15a.59.59 0 0 1-.592-.592v-1.482a.593.593 0 0 1 .593-.592h6.815c.327 0 .593.265.593.592v3.408a4 4 0 0 1-4 4H5.926a.593.593 0 0 1-.593-.593V9.778a4.444 4.444 0 0 1 4.445-4.444h8.296Z\"/></svg>",
  "ri:steam-fill": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"1em\" height=\"1em\" viewBox=\"0 0 24 24\"><path fill=\"currentColor\" d=\"M12.005 2c-5.25 0-9.556 4.05-9.964 9.198l5.36 2.214a2.823 2.823 0 0 1 1.593-.491c.053 0 .105.003.157.005l2.384-3.452v-.049c0-2.08 1.69-3.77 3.77-3.77a3.776 3.776 0 0 1 3.77 3.773c0 2.08-1.691 3.77-3.77 3.77h-.087l-3.397 2.426c0 .043.003.088.003.133A2.826 2.826 0 0 1 9 18.587a2.844 2.844 0 0 1-2.775-2.273l-3.838-1.589C3.574 18.923 7.428 22 12.006 22c5.522 0 9.998-4.477 9.998-10c0-5.522-4.477-10-9.999-10M7.08 16.667c.218.452.595.832 1.095 1.041a2.126 2.126 0 0 0 2.78-2.77a2.123 2.123 0 0 0-2.712-1.178l1.269.526a1.565 1.565 0 0 1-1.204 2.889zm10.74-7.245a2.516 2.516 0 0 0-2.513-2.512a2.513 2.513 0 1 0 2.513 2.512M15.312 7.53A1.89 1.89 0 0 1 17.2 9.418a1.89 1.89 0 0 1-1.888 1.888a1.887 1.887 0 1 1 0-3.776\"/></svg>",
  "ri:wechat-fill": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"1em\" height=\"1em\" viewBox=\"0 0 24 24\"><path fill=\"currentColor\" d=\"M18.575 13.711a.91.91 0 0 0 .898-.898a.895.895 0 0 0-.898-.898a.894.894 0 0 0-.898.898c0 .5.4.898.898.898m-4.425 0a.91.91 0 0 0 .898-.898c0-.498-.4-.898-.898-.898a.894.894 0 0 0-.898.898c0 .5.399.898.898.898m6.567 5.04a.347.347 0 0 0-.172.37c0 .048 0 .098.025.147c.098.417.294 1.081.294 1.106c0 .073.025.122.025.172a.22.22 0 0 1-.221.22c-.05 0-.074-.024-.123-.048l-1.449-.836a.8.8 0 0 0-.344-.098c-.073 0-.147 0-.196.024c-.688.197-1.4.295-2.161.295c-3.66 0-6.607-2.457-6.607-5.505c0-3.047 2.947-5.505 6.607-5.505c3.659 0 6.606 2.458 6.606 5.505c0 1.647-.884 3.146-2.284 4.154M16.674 8.099a9.112 9.112 0 0 0-.28-.005c-4.174 0-7.606 2.86-7.606 6.505c0 .554.08 1.09.228 1.6h-.089a9.966 9.966 0 0 1-2.584-.368c-.074-.025-.148-.025-.222-.025a.832.832 0 0 0-.419.123l-1.747 1.005a.35.35 0 0 1-.148.05a.273.273 0 0 1-.27-.27c0-.074.024-.123.049-.197c.024-.024.246-.834.369-1.324c0-.05.024-.123.024-.172a.556.556 0 0 0-.221-.441C2.059 13.376 1 11.586 1 9.599C1.001 5.944 4.571 3 8.951 3c3.765 0 6.93 2.169 7.723 5.098m-5.154.418c.573 0 1.026-.477 1.026-1.026c0-.573-.453-1.026-1.026-1.026s-1.026.453-1.026 1.026s.453 1.026 1.026 1.026m-5.26 0c.573 0 1.027-.477 1.027-1.026c0-.573-.454-1.026-1.027-1.026c-.572 0-1.026.453-1.026 1.026s.454 1.026 1.026 1.026\"/></svg>"
}

最后,使用方法如下,因为使用了TS,所以有完整的类型提示,妈妈再也不用担心我输错图标名称了!

import Icon from "@/components/Icon";

const Demo = () => {
  return (
    <>
      <Icon name="ri:github-fill" size="1.5rem" className="text-secondary-foreground" />

      <Icon name="my:gitee-fill" size="1.3rem" className="text-[#c01b20]" />

      <Icon name="ri:steam-fill" size="1.5rem" className="text-[#1d3266]" />

      <Icon name="ri:wechat-fill" size="1.5rem" className="text-[#07c160]" />
    </>
  );
};

export default Demo;

效果如下,也是非常之炫酷:

适用于React且支持渲染svg字符串的图标组件