Skip to content

手把手撸后台-svg

vite 篇

安装

bash

npm i vite-plugin-svg-icons  -S

svgicon 封装

vue
<template>
  <!-- 判断是否是外部链接 -->
  <img
    v-if="isExternall"
    :src="props.icon"
    v-bind="$attrs"
    :style="{ width: size + 'px', height: size + 'px' }"
  />
  <!-- 判断是否是内置图标 -->
  <svg v-else v-bind="$attrs" :width="size" :height="size">
    <use :xlink:href="iconName" :style="{ fill: color }"></use>
  </svg>
</template>

<script setup>
const props = defineProps({
  //图标名称,会根据传入的信息来判断是否为外链
  icon: {
    type: String,
    required: true,
  },
  //svg图标颜色
  color: {
    type: String,
  },
  //svg图标大小
  size: {
    type: String,
    required: true,
  },
});
const isExternall = computed(() => /(https?:|mailto:tel:)/.test(props.icon));
const iconName = computed(() => `#icon-${props.icon}`);
</script>

<style scoped></style>

vite.config.js 配置

  • 这里特别注意的就是路径,因为我们是把所有的 svg 文件都放在了 src/assets/icon 文件夹下,所以路径就是 src/assets/icon
js
import { fileURLToPath, URL } from "node:url";
import path from "path";
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import vueDevTools from "vite-plugin-vue-devtools";

import AutoImport from "unplugin-auto-import/vite";

import Components from "unplugin-vue-components/vite"; // 按需加载自定义组件

// 引入svg

import { createSvgIconsPlugin } from "vite-plugin-svg-icons";

// https://vite.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    vueDevTools(),
    AutoImport({
      imports: ["vue", "vue-router"],
      dts: "src/auto-import.d.ts",
    }),
    Components({
      // 解决命名冲突
      directoryAsNamespace: true,
      dts: true, //
      dirs: ["src/components"], // 按需加载的文件夹
      //     resolvers: [   // 设置UI框架自动加载
      //       ElementPlusResolver(),  // Antd   按需加载
      //       AntDesignVueResolver()  // ElementPlus按需加载
      //  ]
    }),
    // 配置svg 图标
    createSvgIconsPlugin({
      // 指定需要缓存的图标文件夹
      iconDirs: [path.resolve(process.cwd(), "src/assets/icon")],
      // 指定symbolId格式
      symbolId: "icon-[name]",
      /**
       * 自定义插入位置
       * @default: body-last
       */
      inject: "body-last" | "body-first",
      /**
       * custom dom id
       * @default: __svg__icons__dom__
       */
      customDomId: "__svg__icons__dom__",
      svgoOptions: {
        plugins: [
          {
            // 清除svg部分属性
            name: "removeAttrs",
            params: { attrs: ["fill", "stroke"] },
          },
        ],
      },
    }),
  ],
  resolve: {
    alias: {
      "@": fileURLToPath(new URL("./src", import.meta.url)),
    },
    extensions: [".js", ".json", ".ts", ".vue"],
  },
});

main.js 引入

js
import "virtual:svg-icons-register";
import svgIcon from "@/components/SvgIcon/index";
const app = createApp(App);
app.component("svgIcon", svgIcon);
app.mount("#app");

使用

html
<svgIcon icon="eye" color="red" size="56" />
<svgIcon
  icon="https://file.jsopy.com/svgAll/chengxuyuan.svg"
  color="red"
  size="56"
/>

webpack 篇幅

安装

bash
npm i --save-dev svg-sprite-loader@6.0.9 --legacy-peer-deps

修改 vue.config.js

  • 特别注意的就是目录 src/icons 目录
js
const { defineConfig } = require("@vue/cli-service");
const path = require("path");

function resolve(dir) {
  return path.join(__dirname, dir);
}

module.exports = defineConfig({
  transpileDependencies: true,
  chainWebpack(config) {
    // 设置 svg-sprite-loader
    config.module.rule("svg").exclude.add(resolve("src/icons")).end();
    config.module
      .rule("icons")
      .test(/\.svg$/)
      .include.add(resolve("src/icons"))
      .end()
      .use("svg-sprite-loader")
      .loader("svg-sprite-loader")
      .options({
        symbolId: "icon-[name]",
      })
      .end();
  },
});

创建 sVgicon 组件

  • 在 components 文件夹下面创建 SvgIcon 文件夹里面创建 index.vue 文件
vue
<template>
  <!--展示外部图标-->
  <div
    v-if="isExternal"
    :style="styleExternalIcon"
    class="svg-external-icon"
    :class="className"
  ></div>
  <!--展示内部图标-->
  <svg v-else class="svg-icon" :class="className" aria-hidden="true">
    <use :xlink:href="iconName" />
  </svg>
</template>

<script setup>
import { defineProps, computed } from "vue";
const props = defineProps({
  // icon图标
  icon: {
    type: String,
    required: true,
  },
  // 图标类名
  className: {
    type: String,
    default: "",
  },
});
/* 判断法则 */
const external = (path) => {
  return /^(https?:|mailto:|tel:)/.test(path);
};
/*
当前图标是否为外部图标,
*/
const isExternal = computed(() => {
  return external(props.icon);
});

/*
外部图标样式,
*/
const styleExternalIcon = computed(() => {
  return {
    mask: `url(${props.icon}) no-repeat 50% 50%`,
    "-webkit-mask": `url(${props.icon}) no-repeat 50% 50%`,
  };
});
/*
内部图标
*/
const iconName = computed(() => {
  return `#icon-${props.icon}`;
});
</script>

<style lang="scss" scoped>
.svg-icon {
  width: 1em;
  height: 1em;
  vertical-align: 0.1em;
  fill: currentColor;
  overflow: hidden;
}
.svg-external-icon {
  background-color: currentColor;
  mask-size: cover !important;
  display: inline-block;
}
</style>
  • 在 src 目录下面新建 icons 文件夹,在下面创立 svg 文件夹把所有的图标都放到下面,然后在 icons 文件夹下面新建 index.js 文件
js
import SvgIcon from "@/components/SvgIcon";

// https://webpack.docschina.org/guides/dependency-management/#requirecontext
// 通过 require.context() 函数来创建自己的 context
// 第一个要搜索的目录,第二个表示是否搜索子目录,第三个表示正则表达式
const svgRequire = require.context("./svg", false, /\.svg$/);
// 此时返回一个 require 的函数,可以接受一个 request 的参数,用于 require 的导入。
// 该函数提供了三个属性,可以通过 require.keys() 获取到所有的 svg 图标
// 遍历图标,把图标作为 request 传入到 require 导入函数中,完成本地 svg 图标的导入
svgRequire.keys().forEach((svgIcon) => svgRequire(svgIcon));

export default (app) => {
  app.component("svg-icon", SvgIcon);
};

修改 main.js 文件

js
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
// 增加的
import installIcons from "@/icons";

const app = createApp(App);

// 增加的
installIcons(app);

app.use(store).use(router).mount("#app");

使用

js
<SvgIcon icon="eye" className="svgbox"></SvgIcon>