likes
comments
collection
share

React项目中使用svg图标

作者站长头像
站长
· 阅读数 14

现在项目中使用图标越来越频繁,图标使用有很多方式,例如雪碧图,字体图标等等,今天介绍一下使用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插件
        // ...其他插件
    ],
};

代码解析

  1. 在使用asset处理的静态资源的配置中排除icon的目录,放置被打包到静态资源
  2. 使用svg-sprite-loader处理svg icon文件,并使用include指定文件目录,不处理其他文件夹下的svg
  3. 设置symbolId: 'svg-[name]'用于指定生成的每个符号(symbol)元素的ID。symbolId 配置选项允许你自定义这些ID,以便更好地控制生成的SVG精灵图中每个图标的唯一标识。
  4. 在插件中使用SpriteLoaderPluginSpriteLoaderPlugin 是与 svg-sprite-loader 一起使用的Webpack插件,它的主要作用是生成SVG精灵图(Sprite),并将生成的精灵图注入到Webpack的输出中,以便在构建后的HTML中使用。
  5. 设置plainSprite: true用于控制生成的 SVG 精灵图的类型。当你将 plainSprite 设置为 true 时,它会生成一个纯粹的 SVG 精灵图,而不会添加额外的元数据或处理。

创建svgIcons文件夹,存放svg图标并批量导入项目中

创建svgIcons文件夹

React项目中使用svg图标

在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)

使用效果

正常状态React项目中使用svg图标hover状态React项目中使用svg图标