1. 基础设置
首先需要安装必要的依赖
# 安装 vite-plugin-svg-icons
npm install vite-plugin-svg-icons -D
# 如果需要使用 svg 组件
npm install @vicons/ionicons5 -D
2. Vite 配置
// vite.config.js
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import path from 'path'
export default defineConfig({
plugins: [
createSvgIconsPlugin({
// 指定 SVG 图标目录
iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')],
// 指定symbolId格式
symbolId: 'icon-[dir]-[name]'
})
]
})
3. 主文件引入
// main.js
import 'virtual:svg-icons-register'
4. 创建 SvgIcon 组件
<!-- src/components/SvgIcon.vue -->
<template>
<svg aria-hidden="true" class="svg-icon">
<use :href="symbolId" :fill="color"/>
</svg>
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps({
// 图标名称
name: {
type: String,
required: true
},
// 图标颜色
color: {
type: String,
default: '#333'
},
// 图标大小
size: {
type: [Number, String],
default: 16
}
})
// 计算图标的symbolId
const symbolId = computed(() => `#icon-${props.name}`)
</script>
<style scoped>
.svg-icon {
width: v-bind('`${props.size}px`');
height: v-bind('`${props.size}px`');
vertical-align: middle;
fill: currentColor;
overflow: hidden;
}
</style>
5. 全局注册组件
// src/components/index.js
import SvgIcon from './SvgIcon.vue'
export default {
install(app) {
app.component('SvgIcon', SvgIcon)
}
}
// main.js
import Components from './components'
app.use(Components)
6. 使用方式
<template>
<!-- 基本使用 -->
<svg-icon name="user" />
<!-- 设置颜色和大小 -->
<svg-icon
name="user"
color="#ff0000"
:size="24"
/>
</template>
7. 进阶用法
1. 创建图标管理器
// src/utils/iconManager.js
export const iconList = {
user: 'user',
home: 'home',
settings: 'settings'
// ... 更多图标
}
export const getIconName = (name) => {
return iconList[name] || name
}
2.封装通用组件:
<!-- src/components/Icon/index.vue -->
<template>
<div class="icon-wrapper" :class="wrapperClass">
<svg-icon
:name="iconName"
:size="size"
:color="color"
@click="handleClick"
/>
<slot></slot>
</div>
</template>
<script setup>
import { computed } from 'vue'
import { getIconName } from '@/utils/iconManager'
const props = defineProps({
name: String,
size: {
type: [Number, String],
default: 16
},
color: String,
disabled: Boolean,
clickable: Boolean
})
const emit = defineEmits(['click'])
const iconName = computed(() => getIconName(props.name))
const wrapperClass = computed(() => ({
'is-disabled': props.disabled,
'is-clickable': props.clickable
}))
const handleClick = (e) => {
if (props.disabled) return
emit('click', e)
}
</script>
<style scoped>
.icon-wrapper {
display: inline-flex;
align-items: center;
justify-content: center;
}
.is-clickable {
cursor: pointer;
}
.is-disabled {
opacity: 0.5;
cursor: not-allowed;
}
</style>
8. 实际应用示例
1.导航菜单:
<template>
<div class="menu">
<div
v-for="item in menuItems"
:key="item.id"
class="menu-item"
>
<svg-icon
:name="item.icon"
:size="20"
:color="item.active ? '#1890ff' : '#666'"
/>
<span>{{ item.title }}</span>
</div>
</div>
</template>
<script setup>
const menuItems = [
{ id: 1, title: '首页', icon: 'home', active: true },
{ id: 2, title: '用户', icon: 'user', active: false },
{ id: 3, title: '设置', icon: 'settings', active: false }
]
</script>
2.按钮组件:
<template>
<button
class="icon-button"
:class="{ 'is-loading': loading }"
>
<svg-icon
v-if="loading"
name="loading"
class="loading-icon"
/>
<svg-icon
:name="icon"
:size="16"
/>
<span><slot></slot></span>
</button>
</template>
<style scoped>
.icon-button {
display: inline-flex;
align-items: center;
gap: 8px;
}
.loading-icon {
animation: spin 1s linear infinite;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
</style>
9.最佳实践
1.组织SVG文件
src/
assets/
icons/
common/ # 通用图标
home.svg
user.svg
business/ # 业务图标
product.svg
order.svg
2.图标命名规范:
// 推荐的命名方式
icon-[模块]-[名称]-[状态]
// 例如
icon-common-home
icon-business-product-active
3.按需加载:
// vite.config.js
createSvgIconsPlugin({
iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')],
symbolId: 'icon-[dir]-[name]',
inject: 'body-last',
customDomId: '__svg__icons__dom__'
})