通过Vite-plugin-svg-icons实现自定义的Icon组件
共计 3.4k words,预计阅读时间 18 min

为了能够通过像UI库的图标组件一样,通过name='icon-name'的形式来引入自己的图标,而不是通过img标签的src属性写长长一串地址,所以通过svg sprite图来进行实现。

原理

svg sprite图的实现原理是利用svg的symbol元素,将每个icon包裹在symbol中,再通过svg的use标签来使用该symbol,也就是最终,svg图标会变成如下的样子

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <symbol class="icon" viewBox="0 0 1024 1024" id="icon名">{{省略的icon path}}</symbol>
    <symbol class="icon" viewBox="0 0 1024 1024" id="icon名">{{省略的icon path}}</symbol>
</svg>

此处的每个symbol都对应着一个元素,在需要使用icon的地方通过svg中的use标签根据icon的Id来进行读取

<svg>
	<use xlink:href="#symbolId"></use>
</svg>

svg sprite图的生成与导入

对于vite项目来说,可以使用vite-plugin-svg-icons插件,对于webpack项目来说可以使用svg-sprite-loader插件。

安装

首先安装vite-plugin-svg-icons插件

npm i vite-plugin-svg-icons

配置

之后在vite.config.ts中对插件进行配置

import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import path from 'path'

export default defineConfig({
  plugins: [
    vue(),
    createSvgIconsPlugin({
    	// 指定需要缓存的图标文件夹
    	iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')]
			// 指定symbolId格式
			symbolId: 'icon-[name]'
    })
  ]
})

之后还需要在src/main.ts中引入注册脚本

import 'virtual:svg-icons-register'

至此svg sprite图已经生成,可以在页面中通过svg标签进行访问。访问的symbolId格式便是设置中的icon-[图标文件名称]

<svg>
	<use xlnk:href='#test'></use>
</svg>

封装图标组件

在现在的情况下,我们仍然需要使用svg标签来引入图标,而不是像UI库一般通过组件形式来引入,因此我们创建一个Icon组件对图标进行封装。

<template>
    <svg :class="'svg-icon ' + classes" :style="{
        width: `${width}px`,
        height: `${height}px`,
        color: color
    }" @click="$emit('click')">
        <use :xlink:href="`#icon-${name}`" />
    </svg>
</template>

<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
    name: 'VIcon',
    props: {
        name: {
            type: String,
            required: true
        },
        width: {
            type: Number,
            default: 60
        },
        height: {
            type: Number,
            default: 60
        },
        color: {
            type: String,
            default: 'deepgrey'
        },
        classes: {
            type: String,
            default: ''
        }
    },
    setup(props) {
        return {
            props
        }
    }
})
</script>

<style scoped>
.svg-icon {
    font-weight: 500;
    fill: currentColor;
    stroke: currentColor;
}
</style>

在上述的代码中,我们将svg标签中的内容放置在组件中,并传入一些控制参数,用于调整图标的显示样式,并注册了点击事件,如果希望处理点击事件则可以在调用侧监听click事件并做相应的处理。

至此,便可在别处通过组件形式来使用图标了。

<template>
  <div>
    <h1>This is an about page</h1>
    <VIcon name="boy" color="lightblue" class="test test2" />
  </div>
</template>

<script setup lang="ts">
import VIcon from '@/components/VIcon.vue'
</script>

也可以在src/main.ts中将VIcon注册为组件,即可在别处使用时不再一一导入VIcon

import VIcon from './components/VIcon.vue'
import App from './App.vue'
...

const app = createApp(App)
...
app.component('VIcon',VIcon)
...

Reference

懒人神器:svg-sprite-loader实现自己的Icon组件

Github文档

vite.config.js配置入门详解

svg-sprite-loader的使用

Vue2/3 使用 svg-sprite-loader 实现 svg 图标按需加载

实现跟随鼠标位置的Tooltip
实现一个门票、卡券样式卡片
copyright  2024   @ Cardy
Powered by Astro | Theme Cloud