在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)

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

相关推荐
雪芽蓝域zzs3 小时前
第4节:el-select 弹窗事件控制(打开 / 关闭、选中事件、弹窗滚动事件)
vue.js·elementui
web打印社区11 小时前
HTML5 静默打印:前端页面怎么调用打印机且尽量不弹窗
前端·javascript·vue.js·pdf·html·html5
雪芽蓝域zzs12 小时前
第3节:el-select 弹窗定位、滚动穿透与挂载容器(popper-append-to-body /teleported)
vue.js·elementui
雪芽蓝域zzs1 天前
第 2 节:基础扩展 - 下拉弹窗常用原生属性
vue.js·elementui
xxwl5851 天前
vue3的入门学习
前端·vue.js·学习
web打印社区1 天前
政务办事大厅:叫号小票、办理回执网页怎么静默出纸
前端·javascript·vue.js·pdf·html·政务
斯内普吖1 天前
(开源)水果蔬菜商城实战指南 基于 Java + SSM + Vue + MySQL
java·vue.js·mysql·开源
ss2731 天前
AI全栈实战 | 2.2-02 React 思维模型:数据不可变 vs Vue 数据可变,两种哲学把复杂度推给谁
前端·vue.js·react.js
天衍四九-1 天前
Docker Compose企业实战系列(三):Vue/React前端项目容器化完整部署
前端·vue.js·docker
墨鱼老师1 天前
SpringBoot+Vue 毕设项目开发踩坑记录(前后端分离)
vue.js·spring boot·毕业设计·课程设计·前后端分离·java 毕设