vue3+vite中批量单独引入svg图片的解决方法 (vite-plugin-svg-icons)

148 阅读1分钟

原理

原理就是通过插件 雪碧图生成插件vite-plugin-svg-icons把指定目录下的svg图片整合打包成一整个svg雪碧图,然后插件会把把整个雪碧图插入到html中,然后引入的时候通过id去调用svg,如下图。

svg__icons__dom

不废话直接上代码

文件路径

项目资源存放路径

vite.config.ts

import { defineConfig } from 'vite'
import uni from '@dcloudio/vite-plugin-uni'
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import { resolve } from 'node:path'
import AutoImport from 'unplugin-auto-import/vite'
import Unocss from 'unocss/vite'

export default defineConfig({
  base: './',
  plugins: [
    AutoImport({
      imports: ['vue', 'uni-app'],
      dts: './src/dts/auto-imports.d.ts',
      eslintrc: {
        enabled: true
      }
    }),
    uni(),
    Unocss(),
    createSvgIconsPlugin({
      iconDirs: [resolve(process.cwd(), 'src/assets/svgs')], // icon存放的目录
      symbolId: 'icon-[name]', // symbol的id
      inject: 'body-last', // 插入的位置
      customDomId: '__svg__icons__dom__' // svg的id
    })
  ],
  server: {
    port: 8080
  },
  resolve: {
    alias: {
      '@': `${resolve(__dirname)}/`
    }
  },
  build: {
    // uno报错处理
    watch: {
      exclude: ['node_modules/**', '/__uno.css']
    }
  }
})

SvgIcon.vue(写个SvgIcon组件统一引入)

<template>
  <svg class="svg-icon" :style="iconStyle" aria-hidden="true">
    <use :xlink:href="symbolId" :fill="color" />
  </svg>
</template>

<script setup lang="ts" name="SvgIcon">
import { computed, CSSProperties } from 'vue'

interface SvgProps {
  name: string // 图标的名称 ==> 必传
  prefix?: string // 图标的前缀 ==> 非必传(默认为"icon")
  iconStyle?: CSSProperties // 图标的样式 ==> 非必传
  color?: string // 填充颜色
}

const props = withDefaults(defineProps<SvgProps>(), {
  prefix: 'icon',
  color: ''
})

const symbolId = computed(() => `#${props.prefix}-${props.name}`)
</script>

<style scoped>
.svg-icon {
  display: inline-block;
  width: 1em;
  height: 1em;
  overflow: hidden;
  vertical-align: -0.15em; /* 因icon大小被设置为和字体大小一致,而span等标签的下边缘会和字体的基线对齐,故需设置一个往下的偏移比例,来纠正视觉上的未对齐效果 */
  outline: none;
  fill: currentcolor; /* 定义元素的颜色,currentColor是一个变量,这个变量的值就表示当前元素的color值,如果当前元素未设置color值,则从父元素继承 */
}
</style>

使用SvgIcon.vue

// main.ts 
// 每个人的项目可能都不一样,只看引入SvgIcon的部分就行
import { createSSRApp } from 'vue'
import App from './App.vue'
import setupStore from './store'
import SvgIcon from './components/SvgIcon'
import 'virtual:uno.css'
import 'virtual:svg-icons-register'

export function createApp() {
  const app = createSSRApp(App)
  app.component('SvgIcon', SvgIcon)
  setupStore(app)
  return {
    app
  }
}
// test.vue 
// name为对应文件名
<SvgIcon
  class="mr-10rpx"
  :style="{ width: '40rpx', height: '40rpx' }"
  :color="stateIndexRef > 0 ? '#fff' : '#999'"
  name="undo"
  @click="handlePre"
/>