在 Vue 3 中一劳永逸地集成 SVG 图标

176 阅读4分钟

在 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/svgs
  • symbolId:这是图标的唯一标识符,格式可自定义,如 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图标的颜色

image.png

因为我已经在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>

输出结果

image.png

通过本文的探索,我们成功地将 SVG 图标的强大功能与 Vue 3 的组件化优势相结合,打造了一套堪称“一劳永逸”的解决方案。

下一步?  立即在您的新项目或现有项目中实践这套方案,亲身体验它带来的畅快感。如果您有更复杂的需求(如多色彩图标、动态加载远程 SVG),这也为您提供了一个完美的基础去进行扩展。

希望本指南能成为您 Vue 开发工具箱中一件得心应手的利器。如果您有更好的想法或遇到了问题,欢迎在评论区交流分享!

Happy coding! 🎉