Vite 项目中 SVG 图标组件化最佳实践
通过
vite-plugin-svg-icons
实现 SVG 图标的自动化管理、全局组件集成和动态样式控制,提升开发效率和项目可维护性。
📦 安装依赖
npm install vite-plugin-svg-icons -D
⚙️ Vite 配置 (vite.config.js)
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import path from 'path'
export default defineConfig({
plugins: [
vue(),
createSvgIconsPlugin({
// 指定 SVG 图标存放目录
iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')],
// 定义 symbolId 生成规则
symbolId: 'icon-[dir]-[name]'
})
]
})
🧩 全局组件实现 (src/components/SvgIcon.vue)
<template>
<svg
aria-hidden="true"
class="svg-icon"
:class="className"
:style="{ color, fontSize: size }"
>
<use :xlink:href="symbolId" />
</svg>
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps({
name: { type: String, required: true },
prefix: { type: String, default: 'icon' },
className: { type: String, default: '' },
color: { type: String }, // 颜色控制属性
size: { type: String } // 尺寸控制属性
})
const symbolId = computed(() => `#${props.prefix}-${props.name}`)
</script>
<style scoped>
.svg-icon {
display: inline-block;
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor; /* 继承父级颜色 */
overflow: hidden;
}
</style>
🌐 全局注册 (main.js)
import 'virtual:svg-icons-register' // 激活 SVG 自动化注册
import SvgIcon from '@/components/SvgIcon.vue'
app.component('SvgIcon', SvgIcon) // 全局注册组件
🚀 使用示例
<!-- 基础用法 -->
<SvgIcon name="search" />
<!-- 进阶用法 -->
<SvgIcon
name="user-profile"
class="icon-highlight"
color="#42b983"
size="24px"
/>
import 'virtual:svg-icons-register'
3. 安装依赖
```shell
npm i vite-plugin-svg-icons -D
- 配置vite.config.js
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-[dir]-[name]',
}),
],
})
- 创建全局组件 (src/components/SvgIcon.vue)
<template>
<svg aria-hidden="true" class="svg-icon" :class="className">
<use :xlink:href="symbolId" />
</svg>
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps({
prefix: {
type: String,
default: 'icon'
},
name: {
type: String,
required: true
},
className: {
type: String,
default: ''
}
})
const symbolId = computed(() => `#${props.prefix}-${props.name}`)
</script>
<style scoped>
.svg-icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
</style>
- 在main.js中全局注册组件
import 'virtual:svg-icons-register'
import SvgIcon from './components/SvgIcon.vue'
app.component('SvgIcon', SvgIcon)
- 在页面中使用
<SvgIcon name="search" />
✨ 优化亮点
- 动态样式控制
- 新增 color 和 size 属性实现动态样式调整
- 保留 className 支持自定义类名
- 语义化改进
- 更清晰的属性命名(name → 图标名称)
- 移除冗余的 prefix 默认值声明
- 样式增强
- 添加 display: inline-block 避免布局偏移
- 使用 currentColor 实现颜色继承
- 错误预防
- 强化 name 属性的必填校验
- 明确注释关键配置的作用
💡 最佳实践建议
-
图标存放路径 src/assets/icons/(支持多级目录结构)
-
命名规范
- 文件命名:search.svg → 使用名:name="search"
- 子目录文件:user/profile.svg → 使用名:name="user-profile"
-
尺寸单位 优先使用 em 单位保持与文本的比例关系
-
颜色控制 通过父级 CSS 的 color 属性或组件的 color prop 控制