React 使用 SVG 的姿势
2022年4月 · 预计阅读时间: 2 分钟
#
前言在项目开发中,跟 svg 打交道可以说必不可少,想对比 png,svg 更可控,还能改变 svg 的样式,体积也会小很多,也相当于一种性能优化。下面看看 React 中使用 svg 的姿势。
svg 它是一种向量图的图片格式,即可伸缩向量图(Scalable Vetor Graphics)。在构建前端应用时经常使用一些图标,相对应我们会比较偏向于使用 svg,那么 svg 有什么好处呢,接下来会说到,这篇文章主要围绕在 React 中如何通过组件的方式使用 svg。
首先看看在项目中使用 svg 有什么好处?
- 压缩后的文件体积小
- 可以无损伸缩到任意尺寸(特别小的尺寸,需要一些 css 特性来解决),放大不会失真
- 设计可控,比如交互和滤镜
那么下面会说说 React 开发中,如何组件化使用 SVG 的,会讲的实现方式有两种 :
- 通过插件
webpack-iconfont-plugin-nodejs
+ 封装 Icon 组件实现; - Vite 构建下使用
vite-plugin-svgr
插件 直接导入实现;
#
实现方式#
封装 Icon 组件实现使用这种方式生成字体文件,然后再使用对应的类型来显示的。
首先需要安装依赖 webpack-iconfont-plugin-nodejs
yarn add webpack-iconfont-plugin-nodejs
# or
npm install webpack-iconfont-plugin-nodejs
再项目更目录创建 svg2font.js 文件
const WebpackIconfontPluginNodejs = require('webpack-iconfont-plugin-nodejs')const path = require('path')
const dir = 'src'
const options = { fontName: 'xxx-icons', // 生成文件名称 cssPrefix: 'b-font', // className 使用的 svg 的前缀名称 svgs: path.join(dir, 'svg/*.svg'), // 获取 svg 的文件夹位置。 fontsOutput: path.join(dir, 'fonts/'), // 创建 fonts 文件夹存放下面输出的文件👇 cssOutput: path.join(dir, 'fonts/font.css'), htmlOutput: path.join(dir, 'fonts/_font-preview.html'), jsOutput: path.join(dir, 'fonts/fonts.js'),}
new WebpackIconfontPluginNodejs(options).build() // 执行并构建生成
这时候我们需要一只命令命令执行 svg2font.js 来生成对应的 fonts 文件。
在 package.json 中添加命令
"scripts": { "svg": "rm -rf fonts; node svg2font.js;"},
将设计给的 svg 图标下载添加到 src/svg 文件夹 📁 下,执行 yarn svg
,生成字体文件。
有了字体文件,那么我们就可以通过类名去直接使用,比如 <i class=“b-font-{svg文件名称}” />
这样虽然可以但是不够优雅,我们可以封装成一个 Icon 组件来使用。
编写 Icon 组件
src/components/Icon/icon.tsx
import { FC, AnchorHTMLAttributes } from "react";import classNames from "classnames";
// React.AnchorHTMLAttributes<HTMLElement> 保留原生标签属性interface IconProps extends React.AnchorHTMLAttributes<HTMLElement> { icon: string; // 存放 svg 文件下的 svg 名称 size?: string | number; // 图标大小}
const Icon: FC<IconProps> = ({ icon, size, className, ...restProps }) => { return ( <i style={{ fontSize: `${size}px` }} className={classNames(`b-font-${icon}`, className)} {...restProps} /> );};
export default Icon;
使用
<Icon icon="wx" size={66} />
效果图
#
Vite 构建下使用插件直接导入方式安装 vite-plugin-svgr
插件依赖
yarn add vite-plugin-svgr
# or
npm install vite-plugin-svgr
在 vite.config.ts 进行配置
import { defineConfig } from "vite";import react from "@vitejs/plugin-react";import svgr from "vite-plugin-svgr";
// https://vitejs.dev/config/export default defineConfig({ plugins: [react(), svgr()],});
重启 run dev
,使用的地方引用导入:
import { ReactComponent as ReactIcon } from "./svg/react.svg";
function App() { const [count, setCount] = useState(0); // console.log(SvgIcon); return ( <div style={{ background: "#F1F1FF", }} > <ReactIcon /> </div> </div> );}
export default App;
在 ts 环境里,会提示 模块 ""*.svg"" 没有导出的成员 "ReactComponent” ,解决办法就是在vite-env.d.ts 文件里面添加 👇:
/// <reference types="vite-plugin-svgr/client" />
这样提示 ts 检查类型的错误就会消失。
或者在 ts.config.json 里面配置
{ "compilerOptions": { // 省略其它配置 "types": ["vite-plugin-svgr/client"] }}
二者其中一个配置了即可。
#
总结上面介绍了两种模式下使用 SVG ,如果是在 webpack 构建下,使用第一种方式,Vite 构建,直接用第二种方式比较方便便捷。对于上面两种方式,社区里面还有更多方案,仅供大家参考。