React项目中使用svg图标
现在项目中使用图标越来越频繁,图标使用有很多方式,例如雪碧图,字体图标等等,今天介绍一下使用svg图标的方式,svg的优势是svg类型的图标是矢量图,可以设置任意宽高而不会失真。下面我们在react项目中为例,使用svg-sprite-loader打包辅助,封装一个SvgIcon
组件。
安装svg-sprite-loader并在webpack中配置
svg-sprite-loader介绍
svg-sprite-loader 是一个Webpack加载器(loader),用于将多个SVG图标文件合并成一个SVG精灵图(Sprite),以减少HTTP请求并提高性能。它可以帮助你将多个SVG图标打包到一个文件中,让你可以通过一个请求来加载所有图标,从而减小页面加载时间。
安装svg-sprite-loader
npm install svg-sprite-loader --save-dev
配置svg-sprite-loader
const path = require('path')
const SpriteLoaderPlugin = require('svg-sprite-loader/plugin')
module.exports = {
// ...其他Webpack配置
module: {
rules: [
{
test: /\.(png|jpe?g|gif|webp|svg|ico)$/,
type: 'asset',
// 静态资源处理排除svg icon所在的目录
exclude: [path.resolve(__dirname, '../src/svgIcons/icons')],
parser: {
dataUrlCondition: {
maxSize: 8 * 1024
}
},
generator: {
filename: 'image/[name].[hash:8][ext]'
}
},
{
test: /\.svg$/, // 匹配SVG文件
include: path.resolve(__dirname, '../src/svgIcons/icons'), // 包括的目录
use: [
{
loader: 'svg-sprite-loader',
options: {
symbolId: 'svg-[name]'
},
}
],
},
],
},
plugins: [
new SpriteLoaderPlugin({ plainSprite: true }), // 启用svg-sprite-loader插件
// ...其他插件
],
};
代码解析
- 在使用
asset
处理的静态资源的配置中排除icon
的目录,放置被打包到静态资源 - 使用
svg-sprite-loader
处理svg icon
文件,并使用include
指定文件目录,不处理其他文件夹下的svg
- 设置
symbolId: 'svg-[name]'
用于指定生成的每个符号(symbol)元素的ID。symbolId 配置选项允许你自定义这些ID,以便更好地控制生成的SVG精灵图中每个图标的唯一标识。 - 在插件中使用
SpriteLoaderPlugin
SpriteLoaderPlugin 是与 svg-sprite-loader 一起使用的Webpack插件,它的主要作用是生成SVG精灵图(Sprite),并将生成的精灵图注入到Webpack的输出中,以便在构建后的HTML中使用。 - 设置
plainSprite: true
用于控制生成的 SVG 精灵图的类型。当你将 plainSprite 设置为 true 时,它会生成一个纯粹的 SVG 精灵图,而不会添加额外的元数据或处理。
创建svgIcons文件夹,存放svg图标并批量导入项目中
创建svgIcons文件夹
在index.js中批量导入文件
const requireAll = (requireContext) => requireContext.keys().map(requireContext)
const svgList = require.context('./icons', false, /\.svg$/)
requireAll(svgList)
在app.tsx中引入文件
import React from 'react'
import DesktopHeader from '@components/desktopHeader'
import './app.less'
import '@src/svgIcons'
function App() {
return (
<div id="electron-app">
<DesktopHeader />
<div className="app-content">APP</div>
</div>
)
}
export default App
此时所有的文件都被导入到项目中,这里这样做的目的是webpack不会主动打包未在项目中导入的文件,所以需要批量导入。
封装SvgIcon组件,并使用
封装SvgIcon组件
import React, { memo, useState } from 'react'
import { Tooltip } from 'antd'
import './svgIcon.less'
type SvgIconProps = {
// 图标名称
svgName: string,
// 图标尺寸,不传时为图标默认24px
iconSize?: number,
/**
* 若该图标需要hover时改变颜色,请先把该图标内置fill属性删除,然后传入两个值,
* iconColor:原始颜色,hoverColor:hover时的颜色
*/
hasHover?: boolean,
// 图标默认颜色
iconColor?: string,
// 图标hover时的颜色
hoverColor?: string,
// 是否需要显示小手
needPointer?: boolean,
// 图标提示文案
toolTipValue?: string
}
function SvgIcon(props: SvgIconProps) {
const {
svgName,
iconSize,
hasHover,
iconColor,
hoverColor,
needPointer,
toolTipValue
} = props
const [svgColor, setSvgColor] = useState(iconColor)
const handleMouseEnter = () => {
if (hasHover) {
setSvgColor(hoverColor)
}
}
const handleMouseLeave = () => {
if (hasHover) {
setSvgColor(iconColor)
}
}
return (
<Tooltip title={toolTipValue} arrow={false}>
<div
id="svg-icon"
style={{
width: iconSize,
height: iconSize,
cursor: needPointer ? 'pointer' : 'normal'
}}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
<svg fill={svgColor}>
<use xlinkHref={`#svg-${svgName}`} />
</svg>
</div>
</Tooltip>
)
}
SvgIcon.defaultProps = {
iconSize: 24,
hasHover: false,
iconColor: '#000000',
hoverColor: '#000000',
needPointer: false,
toolTipValue: ''
}
export default memo(SvgIcon)
使用SvgIcon组件
import React, { memo } from 'react'
import './desktopHeader.less'
import SvgIcon from '@components/svgIcon'
function DesktopHeader() {
return (
<div className="desktop-header">
<SvgIcon
svgName="close-icon"
needPointer
hasHover
iconColor="#666666"
hoverColor="red"
iconSize={32}
toolTipValue="close"
/>
</div>
)
}
export default memo(DesktopHeader)
使用效果
正常状态
hover状态
转载自:https://juejin.cn/post/7274542847659098152