Vue3 使用 svg-sprite-loader 实现 svg 图标按需加载
阅读原文时间:2020年12月19日阅读:8

前面文章有讲到 svg 图标按需加载的优势以及 Vue 如何使用 vue-svg-icon 实现 svg 图标按需载入:

https://www.cnblogs.com/Leophen/p/13201907.html

今天来学习一下使用 svg-sprite-loader 在 Vue3 项目中实现图标按需加载

1、将 email.svg 文件导入项目

<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
  <path d="M4 4H20C21.1 4 22 4.9 22 6V18C22 19.1 21.1 20 20 20H4C2.9 20 2 19.1 2 18V6C2 4.9 2.9 4 4 4Z" stroke="currentColor"
    stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
  <path d="M22 6L12 13L2 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
</svg>

这里将 svg 图标中对应的图标颜色值改为字符串 currentColor,方便使用时控制图标实时颜色

将图标放在特定文件夹下,这里以 @/assets/svg 中导入的 svg 为例

2、安装 svg-sprite-loader

npm i svg-sprite-loader

3、配置 vue.config.js

const path = require("path");

module.exports = {
  // 配置使用stylus全局变量
  chainWebpack: config => {
    const svgRule = config.module.rule("svg");
    svgRule.uses.clear();
    svgRule
      .use("svg-sprite-loader")
      .loader("svg-sprite-loader")
      .options({
        symbolId: "icon-[name]"
      })
      .end();
  }
};

4、新建 SvgIcon.vue 文件,这里可传入 name 属性控制图标类型,传入 size 属性控制图标大小,传入 color 属性控制图标颜色

<template>
  <svg
    class="svg-icon"
    :style="{
      width: props.size + 'px',
      height: props.size + 'px',
      color: props.color
    }"
    @mousedown="clickIcon"
  >
    <use :xlink:href="`#icon-${props.name}`" :fill="props.color" />
  </svg>
</template>

<script lang="ts">
import { defineComponent } from "vue";

export default defineComponent({
  name: "SvgIcon",
  props: {
    name: {
      type: String,
      required: true,
      default: "email"
    },
    size: {
      type: Number,
      default: 32
    },
    color: {
      type: String,
      default: "#000"
    }
  },
  setup(props) {
    return {
      props
    };
  }
});
</script>

5、在 src 目录下新建 plugin.ts

import SvgIcon from "@/pages/components/SvgIcon.vue";

const componentPlugin: any = {
  install: function(vue: any, options: any) {
    if (
      options &&
      options.imports &&
      Array.isArray(options.imports) &&
      options.imports.length > 0
    ) {
      // 按需引入图标
      const { imports } = options;
      imports.forEach((name: any) => {
        require(`@/assets/svg/${name}.svg`);
      });
    } else {
      // 全量引入图标
      const ctx = require.context("@/assets/svg", false, /\.svg$/);
      ctx.keys().forEach(path => {
        const temp = path.match(/\.\/([A-Za-z0-9\-_]+)\.svg$/);
        if (!temp) return;
        const name = temp[1];
        require(`@/assets/svg/${name}.svg`);
      });
    }
    vue.component(SvgIcon.name, SvgIcon);
  }
};
export default componentPlugin;

6、在 main.js(或 main.ts)中引入上面的 plugin 文件

import plugin from "./plugin";

createApp(App)
  .use(plugin, {
    imports: []
  })

7、图标组件的使用

<SvgIcon name="email" :size="24" color="#777" />