项目技术栈,vite, react
Icon组件的封装
项目打包完成上线后,有可能不连外网,因此要求所有的icon为本地文件,这里封装本地svg与antd两种图标
我们先看看最终的使用效果是怎么样的, 传入name,color,size
import Icon from '@/component/Atoms/Icon'
const Demo = () => {
return (
<div>
<Icon name='airplay' color='#ff0000' size='100px' />
<Icon.Ant name='DownCircleOutlined' color='#366213' size='100px' />
</div>
)
}
export default Demo
1,封装Icon
1.1 AntdIcon
封装antd icon首先要引入,4.X版本后,antd不允许使用
<Icon type='IconName' />的写法,必须使用<IconName />, 我们当然可以手动引入所有的icon,然后进行封装,但是不够优雅,这边提供两种思路供参考。
// case1
import React from 'react'
import { IconProps } from '.'
import * as icon from '@ant-design/icons'
interface AntIconProps extends IconProps {}
const AntIcon: React.FC<AntIconProps> = (props) => {
const { name, color ='#555', size = '1em' } = props
const antIcon = (name: string) => {
return React.createElement(icon[name], {
style:{
fontSize: size,
color
}
})
}
return (
<>
{antIcon(name)}
</>
)
}
export default AntIcon
// case2
import React, { lazy } from 'react'
import { IconProps } from '.'
interface AntIconProps extends IconProps {}
const AntIcon: React.FC<AntIconProps> = (props) => {
const { name, color ='#555', size = '1em' } = props
const lazyLoadIcon = (name: string) => {
return <React.Suspense fallback={<></>}>
{React.createElement(lazy(() => import('@ant-design/icons').then(module => {
return {default: module[name]};
})), {
style:{
fontSize: size,
color
}
})}
</React.Suspense>
}
return (
<>
{lazyLoadIcon(name)}
</>
)
}
export default AntIcon
1.2 LoacalIcon
本地的svg在项目中封装成icon组件的样子使用,需要做以下几件事
安装vite-plugin-svg-icons插件,并在vite.config.ts文件中进行相关配置
//
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import path from 'path'
import svgr from 'vite-plugin-svgr'
import viteCompression from 'vite-plugin-compression'
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
plugins: [
react(),
svgr(),
createSvgIconsPlugin({
// Specify the icon folder to be cached
iconDirs: [path.resolve(process.cwd(), 'src/yourSvgPath')],
// Specify symbolId format
symbolId: 'local-icon-[svgName]',
// 删除svg文件stroke属性,使得icon颜色能够修改
svgoOptions:{
plugins: [
{
name: "removeAttrs",
params: {attrs:['stroke']}
},
]
},
/**
* custom insert position
* @default: body-last
*/
inject: 'body-last',
/**
* custom dom id
* @default: __svg__icons__dom__
*/
customDomId: '__svg__icons__dom__',
})
],
在main.js中引入插件
// 引入插件,用于显示本地svgIcon
import 'virtual:svg-icons-register'
封装组件LoacalIcon
import React from 'react';
import { IconProps } from '.';
interface LocalIconProps extends IconProps {}
const LocalIcon: React.FC<LocalIconProps> = (props) => {
const {name, color = 'currentColor', size = '1em'} = props;
const symbolId = `#local-icon-${name}`
return (
<svg stroke={color} width={size} height={size} aria-hidden="true">
<use xlinkHref={symbolId} />
</svg>
)
}
export default LocalIcon;
2,统一导出
import React from 'react';
import AntIcon from './AntIcon';
import Local from './LoacalIcon';
export interface IconProps extends JtElement {
name:string
color?:string
size?:string
}
interface IconSubComponents {
Ant: React.FC<IconProps>;
}
/**
* 图标组件接口
* You can use it in following ways:
* - <Icon name="xxx" color="xxx" size="xxx" />
* - <Icon.Ant name="xxx" color="xxx" size="xxx" />
*
* @param props IconProps
* @returns React Component
*/
const Icon: React.FC<IconProps> & IconSubComponents = (props) => {
const { ...rest } = props;
return (
<Local {...rest} />
);
};
Icon.Ant = AntIcon;
export default Icon;
大功告成,这就封装了一个可以同时使用本地svgIcon与antdIcon的Icon组件