本文最后更新于: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: '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 图标按需加载