前言
在项目开发中经常需要使用图标,有的直接使用UI切图,有的使用阿里图标库。阿里图标库里面的iconFont可以设置color、fontSize 是我们使用的主流。目前我在项目中使用svg格式来展示icon。
项目架构:umi3.5 + react hooks
为什么使用svg
- SVG 可被非常多的工具读取和修改(比如记事本)
- SVG 与 JPEG 和 GIF 图像比起来,尺寸更小,且可压缩性更强。
- SVG 是可伸缩的
- SVG 图像可在任何的分辨率下被高质量地打印
- SVG 可在图像质量不下降的情况下被放大
- SVG 图像中的文本是可选的,同时也是可搜索的(很适合制作地图)
- SVG 可以与 Java 技术一起运行
- SVG 是开放的标准
- SVG 文件是纯粹的 XML
为什么不用font class了
- 引入复杂,需要引入iconfont.css、iconfont.js、iconfont.woff等
- 更新麻烦,每次版本迭代更新,多一样少一个都需要覆盖一整个文件,多人开发不友好(主要原因)
- 上手需要成本、心智负担,尤其是较为青涩的成员独自修改风险较高
- 代码难看,经常看到在项目入口文件一大串import
一、目录创建
新建一个专门存放svg的目录
二、umirc.ts 配置
yarn add svg-sprite-loader
svg-sprite-loader 的官方解释是:一个用于创建 svg 雪碧图的 Webpack 加载器。这个加载器现在已经被 JetBrains 公司收录和维护了。通俗的讲:svg-sprite-loader 会把你引入的 svg 塞到一个个 symbol 中,合成一个大的 svg,最后将这个大的 svg 放入 body 中。symbol 的 id 如果不特别指定,就是你的文件名。
import { defineConfig } from 'umi';
export default defineConfig({
...
chainWebpack(config: any) {
// 用svg-sprite-loader制作 svg-symbol,让我们可以直接使用 svg-use。
config.module
.rule('svg')
.exclude.add(path.resolve(__dirname, './src/assets/svg')).end(); // 不包含的采用默认的 svg 规则
config.module.rule('image')
.test(/\.svg$/i)
.include.add(path.resolve(__dirname, './src/assets/svg')).end()
.use('svg-sprite-loader')
.loader(require.resolve('svg-sprite-loader'))
}
});
配置成功后效果
三、封装SvgIcon组件
/*
* @Descripttion: SvgIcon组件
* @Author: JayShen
* @Date: 2022-06-23 17:55:58
* @LastEditors: JayShen
* @LastEditTime: 2022-09-14 15:50:10
*/
import React from 'react';
import classNames from 'classnames';
import style from "./index.module.less"
try {
// 利用 webpack 提供的 require.context API 来创建自己的 context module 动态引入 icon
const importAll = (requireContext: __WebpackModuleApi.RequireContext) => requireContext.keys().forEach(requireContext);
importAll(require.context('@/assets/svg', true, /\.svg$/));
} catch (error) {
console.error('importAll:', error);
}
type TCursor = 'auto' | 'pointer' | 'wait' | 'help' | 'move'
export type IconProps = {
/** svg名称 */
name: string;
onClick?: () => void;
color?: string;
className?: string;
size?: number;
/** 鼠标形状 */
cursor?: TCursor;
style?: any
};
const SvgIcon: React.FC<IconProps> = (props) => {
const { name, color, size = 20, onClick, className, cursor = 'auto' } = props
return (
<svg
{
...props
}
onClick={onClick}
className={classNames(style.svgIcon, className)}
style={{ color, fontSize: size && `${size}px`, cursor: cursor, ...props.style }}
aria-hidden="true"
>
<use xlinkHref={'#' + name} />
</svg>
);
};
export default SvgIcon;
// index.module.less
.svgIcon{
width: 1em;
height: 1em;
fill: currentColor;
overflow: hidden;
display: inline-block;
}
四、使用
将组件引入后,在页面直接使用,name就是svg文件名,极其方便
<SvgIcon
name="shanchu"
size={16}
color="#4389f1"
/>
解决痛点
- 新增便捷,每次新增只需要新建svg文件,在阿里图标库点击【复制svg代码】即可
- 心智负担小,团队只要一个人配置好,后续成员使用完全不需要修改配置、也不需要知道其原理
- 使用简单,搭配组件后使用简单,只需要传入name
- 代码优雅,不需要一堆import