在vite+Vue3项目中使用 自定义svg 图标,借助vite-plugin-svg-icons 封装SvgIcon组件

一. 实现效果:

组件使用:

html 复制代码
<SvgIcon class="icon" name="SpaceIcons-pluto" />

二. 环境

json 复制代码
{
	"vite": "npm:rolldown-vite@7.2.5",
	"vue": "^3.5.24",
	"vite-plugin-svg-icons": "^2.0.1",
}

三. 实现

1. 下载 vite-plugin-svg-icons

bash 复制代码
# 使用npm
npm install vite-plugin-svg-icons -D

# 使用yarn
yarn add vite-plugin-svg-icons -D

# 使用pnpm
pnpm install vite-plugin-svg-icons -D

2. 配置 vite.config.ts

ts 复制代码
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons';
import * as path from "node:path";

// https://vite.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    createSvgIconsPlugin({
      // 指定需要缓存的图标文件夹
      iconDirs: [path.resolve(process.cwd(), 'src/assets/svgs')],
      // 指定symbolId格式,与组件内的 computed 逻辑对应
       symbolId: 'icon-[dir]-[name]', // 例如:icon-home
      // 图标存在指定目录的子目录下 使用下面这行 👇👇👇
      // symbolId: 'icon-[dir]-[name]', // 例如:icon-menu-home
    }),
  ],
})

3. main.ts 中引入

ts 复制代码
import { createApp } from 'vue'
// ↓↓↓ 加入下面这两行, @ts-ignore 这个用来忽略ts校验, @ts-ignore可省略
// @ts-ignore
import 'virtual:svg-icons-register'
// ↑↑↑
import App from './App.vue'

const app = createApp(App)

3. 封装 SvgIcon

组件位置:components\SvgIcon\index.vue

↑ ↑ ↑ 组件位置看自己喜好

html 复制代码
<template>
  <svg
    aria-hidden="true"
    class="svg-icon"
    :class="className"
    :style="style"
  >
    <use :xlink:href="symbolId" />
  </svg>
</template>

<script setup lang="ts">
import { computed } from 'vue'

const props = defineProps({
  // 图标名称,对应SVG文件名
  name: {
    type: String,
    required: true
  },
  // 图标前缀,需与vite.config.ts中的symbolId配置对应
  prefix: {
    type: String,
    default: 'icon'
  },
  // 图标颜色
  color: {
    type: String,
    default: ''
  },
  // 图标尺寸,支持字符串和数字类型
  size: {
    type: [String, Number],
    default: ''
  },
  // 自定义类名
  className: {
    type: String,
    default: ''
  }
})

// 计算symbolId,格式为"#前缀-图标名"
const symbolId = computed(() => `#${props.prefix}-${props.name}`)

// 计算样式类名
const className = computed(() => {
  return {
    [`svg-icon-${props.name}`]: !!props.name,
    [props.className]: !!props.className
  }
})

// 计算内联样式
const style = computed(() => {
  const style: Record<string, string> = {}

  if (props.size) {
    style.width = `${props.size}px`
    style.height = style.width
  }

  if (props.color) {
    style.color = props.color
    style.fill = props.color
  }

  return style
})
</script>

<style scoped>
.svg-icon {
  width: 1em;
  height: 1em;
  vertical-align: -0.15em;
  fill: currentColor;
  overflow: hidden;
}
</style>

4. 使用

按需引入

html 复制代码
<template>
   <SvgIcon class="icon" name="SpaceIcons-pluto" />
</template>

<script lang="ts" setup>
import  SvgIcon from "@/components/SvgIcon/index.vue";
</script>

全局注册

文件位置: components\SvgIcon\index.ts ←← 按照自己喜好

ts 复制代码
import SvgIcon from './index.vue'
export default {
	install(app){
		 app.component('SvgIcon', SvgIcon)
	}
}

main.ts 中引入

ts 复制代码
import { createApp } from 'vue'
// ↓↓↓ 加入下面这两行, @ts-ignore 这个用来忽略ts校验, @ts-ignore可省略
// @ts-ignore
import 'virtual:svg-icons-register'
// ↑↑↑
import App from './App.vue'
import SvgIcon form '@/components/SvgIcon/index.ts'

const app = createApp(App)

使用过程中如果有什么疑问可以私信,评论也行

相关推荐
迅速的自行车1 天前
从一段模板说起
前端·javascript·vue.js
阿奇__1 天前
uniapp微信小程序图片上传含回显组件(拍照,相册)
前端·javascript·vue.js
前端甜糖1 天前
前端如何实现在线预览office常见文件功能?
前端·vue.js
ljs6482739511 天前
智慧商城(Smart Mall):基于 Spring Boot + Vue 3 的现代化电商平台实战
linux·vue.js·spring boot·后端
析数塔1 天前
2026前端框架深度解析:React Compiler、Angular Zoneless、Vue 3.5重写游戏规则
前端·vue.js·react.js
paopaokaka_luck2 天前
英语单词学习系统的设计与实现(基于艾宾浩斯遗忘曲线的智能复习机制、语音朗读、多题型测试与错题自动收录、Echarts图形化分析)
vue.js·spring boot·后端·echarts
Momo__2 天前
Vite 8.1 打包开发模式——10000 组件冷启动 15 倍,"No Bundle Dev" 七年后被自己终结
前端·vue.js·vite
HUMHSX2 天前
Vue 组件通信核心知识点梳理
javascript·vue.js·ecmascript
妙码生花2 天前
从 PHP 到 AI + Golang,程序员自救转型手记(二十六):icon 组件封装
前端·vue.js·typescript
李明卫杭州2 天前
Vue2 & Vue3 中 Router `props` 配置详解:彻底摆脱 `$route` 依赖
前端·vue.js·前端框架