使用vite的svg插件:vite-plugin-svg-icons,实现图标化

svgicon实现效果图
Snipaste_2025-06-14_09-50-39.png
vite-plugin-svg-icons 是一款专为Vite构建工具设计的SVG图标管理插件,其核心价值在于通过自动化雪碧图生成和组件化方案,解决前端项目中SVG图标管理混乱、重复请求等痛点。

1.下载依赖 vite-plugin-svg-icons

pnpm i vite-plugin-svg-icons -D

2.配置vite.config.js

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'node:path'
import process from 'node:process'
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'

// https://vite.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    createSvgIconsPlugin({
      // 指定需要缓存的图标文件夹
      iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')],
      // 指定 symbolId 格式
      symbolId: 'icon-[dir]-[name]',
      svgoOptions: true, 
    })
  ],
})

3.创建Svg组件

<template>
  <svg
    aria-hidden="true"
    :class="svgClass"
    v-bind="$attrs"
    :style="{ color, fill: color, width: iconSize, height: iconSize }"
  >
    <use :xlink:href="iconName"></use>
  </svg>
</template>

<script setup>
import { computed } from 'vue'

const props = defineProps({
  name: {
    type: String,
    default: '',
    required: true
  },
  color: {
    type: String,
    default: ''
  },
  size: {
    type: [String, Number],
    default: 20
  }
})

// 判断传入的值是否带有单位,如果没有就默认用px单位
const getUnitValue = (value) => {
  return /(px|em|rem|%)$/.test(value.toString()) ? value : `${value}px`
}

const iconSize = computed(() => {
  return getUnitValue(props.size)
})

const iconName = computed(() => `#icon-${props.name}`)

const svgClass = computed(() => {
  return props.name ? `svg-icon icon-${props.name}` : 'svg-icon'
})
</script>

<style scoped>
.svg-icon {
  width: auto;
  height: auto;
  vertical-align: middle;
  flex-shrink: 0;
}
</style>

4.main.js引入'virtual:svg-icons-register'

import 'virtual:svg-icons-register'

5.使用组件

<template>
    <div class="icon-container">
        <div v-for="iconName in iconNames" :key="iconName" class="icon-item">
            <SvgIcon :name="iconName" :size="20" />
            <span>{{ iconName }}</span>
        </div>
    </div>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import SvgIcon from './components/SvgIcon/index.vue'

function getAllIconNames() {
    const svgModules = import.meta.glob('./assets/icons/*.svg', { eager: true })

    // 提取文件名(不带扩展名)
    return Object.keys(svgModules).map(path => {
        const fileName = path.split('/').pop()
        return fileName.replace('.svg', '')
    })
}

const iconNames = ref([])

onMounted(() => {
    iconNames.value = getAllIconNames()
})

</script>


<style scoped>
.icon-container {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
    gap: 16px;
    padding: 16px;
}

.icon-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    padding: 8px;
    border: 1px solid #eee;
    border-radius: 4px;
}

.icon-item span {
    font-size: 12px;
    text-align: center;
}
</style>
无标签
评论区
头像
文章目录