头图

资源引入式组件的方式使用

pnpm install vite-svg-loader --save-dev
// vite.config.ts
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import svgLoader from "vite-svg-loader";

export default defineConfig({
  plugins: [
      vue(), 
      svgLoader()
  ]
}

页面使用
image.png

<template>
  <div>
    <Cake />
  </div>
</template>
  
<script setup>
import Cake from "@assets/svg/cake.svg";
</script>

效果:
image.png

svg雪碧图-组件式直接引入

资源引入的弊端:
在上面第一种svg的使用方式中,svg是以资源引入的方式使用的,那就意味每使用一个svg就要import一次,在vite中,import算是一个http请求,如果页面使用多个svg,那么就要引入多次,比较消耗性能,如下:

import Cake1 from "@assets/svg/cake1.svg";
import Cake2 from "@assets/svg/cake2.svg";
import Cake3 from "@assets/svg/cake3.svg";
import Cake4 from "@assets/svg/cake4.svg";

如果页面中有100个svg,那么就要发送100个http请求,相当麻烦。

解决方法:
所以我们可以将svg以文件夹的形式生成雪碧图,这样我们就能直接使用该文件夹下的所有svg了。

pnpm i vite-plugin-svg-icons -D
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons';
import path from 'path'; // ts如果报错 pnpm i @types/node -D
export default () => {
  return {
    plugins: [
      createSvgIconsPlugin({
        // 配置src下存放svg的路径,这里表示在src/icons文件夹下
        iconDirs: [path.resolve(process.cwd(), 'src/icons')],
        symbolId: 'icon-[dir]-[name]',
      }),
    ],
  };
};

image.png
创建svg组件

<template>
  <svg
    aria-hidden="true"
    :class="svgClass"
    :style="{
      color: color,
      fill: color,
      width: iconSize,
      height: iconSize
    }"
    v-bind="$attrs"
  >
    <use :xlink:href="iconName" :fill="color" />
  </svg>
</template>

<script lang="ts" setup>
import { computed } from "vue";
defineOptions({ name: "SvgIcon" });
const props = defineProps({
  name: {
    type: String,
    default: ""
  },
  color: {
    type: String,
    default: ""
  },
  size: {
    type: [Number, String],
    default: 15
  }
});

// 判断传入的值,是否带有单位,如果没有,就默认用px单位
const getUnitValue = (value: string | number): string | number => {
  return /(px|em|rem|%)$/.test(value.toString()) ? value : value + "px";
};

// svg大小
const iconSize = computed<string | number>(() => {
  return getUnitValue(props.size);
});

// svg名称-对应资源文件夹的svg名称
const iconName = computed<string>(() => `#icon-${props.name}`);

// svg动态类名
const svgClass = computed<string>(() => {
  if (props.name) return `svg-icon icon-${props.name}`;
  return "svg-icon";
});
</script>

<style lang="scss" scope>
.svg-icon {
  width: auto;
  height: auto;
  vertical-align: middle;
  flex-shrink: 0;
}
</style>

在main.ts中使用依赖

import "virtual:svg-icons-register";
import SvgIcon from "./components/SvgIcon/index.vue"; // 全局svg图标组件

const app = createApp(App);
app.component("SvgIcon", SvgIcon); // 全局组件挂载
app.mount("#app");

在页面使用,通过名称指向配置路径下的资源文件

<template>
  <div>
    <SvgIcon :name="'snow'" :size="20"/>
  </div>
</template>

<script setup lang="ts"></script>
<style lang="scss" scoped></style>

页面效果
image.png


兔子先森
405 声望17 粉丝

致力于新技术的推广与优秀技术的普及。