Appearance
Icon 图标处理方案:SvgIcon
在我们的日常开发中,对于项目中所使用的icon图标,一共分为两类:
element-plus的图标- 自定义的
svg图标 
对于 element-plus 的图标我们可以直接通过 el-icon 来进行显示,但是自定义图标的话,我们暂时还缺少显示的方式,所以说我们需要一个自定义的组件,来显示我们自定义的 svg 图标。
那么对于这个组件的话,它应该拥有两种能力:
- 显示外部 
svg图标 - 显示项目内的 
svg图标 
基于以上概念,我们可以创建出以下对应代码:
创建 components/SvgIcon/index.vue:
vue
<template>
  <!-- 外部图标 -->
  <div
    v-if="isExternal"
    :style="externalIconStyle"
    :class="className"
    class="svg-external-icon svg-icon"
  ></div>
  <!-- 内部图标 -->
  <svg v-else :class="className" class="svg-icon">
    <use :xlink:href="symbolId" />
  </svg>
</template>
<script setup lang="ts">
  import { computed } from 'vue'
  interface Props {
    icon: string // 外部资源或内部图标
    className?: string
  }
  const props = withDefaults(defineProps<Props>(), {
    icon: '',
    className: '',
  })
  const external = (path: string) => {
    return /^(https?:|mailto:|tel:)/.test(path)
  }
  // 判断是否为外部资源
  const isExternal = computed(() => external(props.icon))
  // 外部图标样式
  const externalIconStyle = computed(() => {
    return {
      mask: `url(${props.icon}) no-repeat 50% 50%`,
      '-webkit-mask': `url(${props.icon}) no-repeat 50% 50%`,
    }
  })
  // 内部图标use 引用的dom id
  const symbolId = computed(() => `#icon-${props.icon}`)
</script>
<style lang="scss" scoped>
  .svg-icon {
    width: 1em;
    height: 1em;
    vertical-align: -0.15em;
    fill: currentColor;
    overflow: hidden;
  }
  .svg-external-icon {
    background-color: currentColor;
    mask-size: cover !important;
    -webkit-mask-size: cover !important;
    display: inline-block;
  }
</style>
然后全局注册该组件
ts
import SvgIcon from '@/components/SvgIcon/index.vue'
const app = createApp(App).use(ElementPlus).use(router).use(store)
app.component('svg-icon', SvgIcon)
app.mount('#app')
外部图标
对于外部图标,直接传入url即可
html
<span class="svg-container">
  <svg-icon icon="https://res.lgdsunday.club/user.svg"></svg-icon>
</span>
内部图标
一般是将所有svg图标放到一个统一的目录下 
然后通过插件生成svg雪碧图挂载到body末尾

每个<Symbol>元素的id和目录中svg的文件名绑定
因为在<SvgIcon>内部, 我们是通过#icon-拼接props.icon
ts
const symbolId = computed(() => `#icon-${props.icon}`)
所以,在使用<SvgIcon>组件时,只需将icon属性设置为相应的svg文件名即可
html
<svg-icon icon="password"></svg-icon>
插件
vite插件: vite-plugin-svg-icons
- vite.config.js
 
jsplugins: [ vue(), vueJsx({ // options are passed on to @vue/babel-plugin-jsx }), createSvgIconsPlugin({ // 指定需要缓存的图标文件夹 iconDirs: [resolve(process.cwd(), 'src/assets/svgs')], // 指定symbolId格式 symbolId: 'icon-[dir]-[name]', }), ],- main.ts
 
tsimport 'virtual:svg-icons-register'webpack插件: svg-sprite-loader