在 Vue 3 项目中,手动引入 SVG 图标不仅繁琐,更是项目维护的痛点。本文旨在彻底解决这一问题,通过封装一个通用的全局组件,实现图标的自动化管理与高性能应用。您将学会如何一劳永逸地构建一套支持按需使用、样式可控的图标系统,极大提升开发体验与项目可维护性。
安装必要的依赖
首先需要安装处理svg的vite插件,vite-plugin-svg-icons:核心插件,用于自动导入和处理 SVG 文件,并将其转换为 SVG Sprite, fast-glob:一个快速的文件匹配库,vite-plugin-svg-icons依赖它来高效查找 SVG 文件
npm install vite-plugin-svg-icons fast-glob -D
# 或
pnpm add vite-plugin-svg-icons fast-glob -D
# 或
yarn add vite-plugin-svg-icons fast-glob --dev
配置vite插件
在vite.config.ts中配置插件,来指定你的 SVG 图标存放路径和生成规则
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// 自动按需引入组件
import Components from 'unplugin-vue-components/vite'
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
export default defineConfig(() => {
return {
plugins: [
vue(),
Components({
// 自动按需引入组件
resolvers: [
ElementPlusResolver(),
ArcoResolver({
// 自动按需引入 Arco Design 组件
sideEffect: true,
}),
], // 自动按需引入 Element Plus 组件
dirs: ['src/components'], // 按需引入的组件目录
dts: 'src/components.d.ts', // 生成 `components.d.ts` 文件
}),
// 配置svg插件
createSvgIconsPlugin({
// 指定需要缓存的图标文件夹
iconDirs: [fileURLToPath(new URL('./src/assets/icons', import.meta.url))],
// 指定symbolId格式
symbolId: 'icon-[name]',
}),
],
}
})
关键点:
iconDirs:务必修改为你的 SVG 文件所在的真实目录,常见的有src/assets/icons或src/assets/svgssymbolId:这是图标的唯一标识符,格式可自定义,如icon-[dir]-[name](包含目录名)
在主入口文件注册,一般在(main.ts)中注册
// main.ts
import { createApp } from 'vue'
import App from './App.vue'
// 引入 SVG 注册脚本
import 'virtual:svg-icons-register'
const app = createApp(App)
app.mount('#app')
作用: 这行代码会运行插件,将你指定目录下的所有 SVG 图标自动合并成一个 SVG Sprite(雪碧图),并注入到 DOM 中,这样你就能在任何组件中通过 <use>标签引用了
封装 SVG 图标组件
创建一个通用的 Vue 组件来方便地使用图标,在 src/components/目录下创建 SvgIcon.vue文件
<template>
<svg :class="svgClass" :style="svgStyle" aria-hidden="true">
<use :xlink:href="symbolId" />
</svg>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import type { CSSProperties } from 'vue' // 用于扩展在样式属性绑定上允许的值的类型
const props = defineProps({
name: {
type: String,
required: true,
},
size: {
type: String,
default: '1em',
},
// 图标颜色
color: {
ype: String,
default: 'currentColor', // 默认继承父元素的文字颜色
},
className: {
type: String,
default: '',
},
})
// 计算属性,生成最终的 symbolId,需要与 vite.config.ts 中配置的格式匹配
const symbolId = computed(() => `#icon-${props.name}`)
const svgClass = computed(() => (props.className ? `svg-icon ${props.className}` : 'svg-icon'))
const svgStyle = computed<CSSProperties>(() => {
return {
width: typeof props.size === 'number' ? `${props.size}px` : props.size,
height: typeof props.size === 'number' ? `${props.size}px` : props.size,
fill: props.color,
}
})
</script>
<style lang="scss" scoped>
.svg-icon {
display: inline-block;
vertical-align: -0.125em; // 修正图标垂直对齐问题
line-height: 1;
fill: currentColor; // 让图标颜色继承自父级的color属性
}
</style>
使用 SVG 图标组件
注意: 引入svg图标之前,需要先删除svg文件中所有的fill、fill-opacity、fill-rule属性,如果不删除svg中的这些属性那么svg图片无法通过color属性,来修改svg图标的颜色
因为我已经在vite.config.ts配置了自动按需引入组件,所以不需要再将SvgIcon组件注册成全局组件,直接在其他组件中使用即可,图标可以去iconfont下载,然后引入到项目中
// HelloWorld.vue 组件
<template>
<div>
<!-- 基本使用 -->
<svg-icon name="message" size="16" />
<!-- 自定义大小和颜色 -->
<svg-icon name="home" size="24" />
<svg-icon name="personal" size="36" color="#fa8c16" />
<!-- 通过 CSS 控制 -->
<svg-icon name="personal" size="56" class="custom-icon" />
</div>
</template>
<style scoped lang="scss">
.custom-icon {
color: blue; /* 通过 CSS 控制颜色 */
font-size: 48px; /* 通过 font-size 控制大小 (因为默认是 1em) */
}
</style>
输出结果
通过本文的探索,我们成功地将 SVG 图标的强大功能与 Vue 3 的组件化优势相结合,打造了一套堪称“一劳永逸”的解决方案。
下一步? 立即在您的新项目或现有项目中实践这套方案,亲身体验它带来的畅快感。如果您有更复杂的需求(如多色彩图标、动态加载远程 SVG),这也为您提供了一个完美的基础去进行扩展。
希望本指南能成为您 Vue 开发工具箱中一件得心应手的利器。如果您有更好的想法或遇到了问题,欢迎在评论区交流分享!
Happy coding! 🎉