通过Vite-plugin-svg-icons实现自定义的Icon组件

本文最后更新于:2024年7月22日 晚上

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

原理

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

1
2
3
4
<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来进行读取

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

svg sprite图的生成与导入

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

安装

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

1
npm i vite-plugin-svg-icons

配置

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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中引入注册脚本

1
import 'virtual:svg-icons-register'

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

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

封装图标组件

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<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事件并做相应的处理。

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

1
2
3
4
5
6
7
8
9
10
<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

1
2
3
4
5
6
7
8
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 图标按需加载


通过Vite-plugin-svg-icons实现自定义的Icon组件
http://starnight.top/2024/07/13/通过Vite-plugin-svg-icons实现自定义的Icon组件/
作者
Cardy Xie
发布于
2024年7月13日
许可协议