svg属性动态绑定组件

534 阅读1分钟

<svg-icon
  name="pub_attri_icon"
  fill="white"
  :color="isHover ? '#0067d1' : '#777777'"
  size="22"
></svg-icon>

参数说明

实现方式

Vue2

引入svg-sprite-loader

npm install vite-plugin-svg-icons -D

svg-sprite-loader 是一个插件,它可以将 SVG 图片拼接成 SVG Sprites(SVG雪碧图),放到页面中,其它地方通过 use 复用。它的工作原理是利用 svg 的 symbol 元素,将每个 icon 包括在 symbol 中,通过 use 元素使用该 symbol 。这样可以减少 HTTP 请求,提高页面加载速度 。

创建SvgIcon.vue文件

<template>
  <svg aria-hidden="true" :style="getStyle">
    <title>{{ title }}</title>
    <use :xlink:href="symbolId" />
  </svg>
</template>

<script>

export default {
  name: "SvgIcon",
  props: {
    name: {
      type: String,
      required: true
    },
    size: {
      type: [Number, String],
      default: 12
    },
      width: {
      type: [Number, String],
    },
    height: {
      type: [Number, String],
    },
    title: {
      type: [Number, String],
      default: '',
    },
    color: {
      type: String,
      default: "none"
    },
  },
  computed: {
    /*
     * 某些图标可能需要保持特定的宽高比,就可以单独设置宽度和高度(例如100*200,但svg只能等比放大缩小,
       图标显示尺寸还是以小的值为准,相当于页面占位100*200,图表本身大小还是100*100,然后y轴居中的效果
     * */
    getStyle() {
      const width = this.width ?? this.size;
      const height = this.height ?? this.size;
      return {
        width: `${width.toString().replace('px', '')}px`,
        height: `${height.toString().replace('px', '')}px`,
        color: this.color,
    };
    },
    symbolId() {
      return `#icon-${this.name}`;
    }
  }
};
</script>

vite.config.js配置

chainWebpack: config => {
    config.module
      .rule("svg")
      .exclude.add(resolve("src/assets/icons")) // svg的存储地址
      .end();
    config.module
      .rule("icons")
      .test(/.svg$/)
      .include.add(resolve("src/assets/icons")) // svg的存储地址
      .end()
      .use("svg-sprite-loader")
      .loader("svg-sprite-loader")
      .options({
        symbolId: "icon-[name]" // 指定svg的symbolId
      })
      .end();
  },

配置requireSvg.js注册组件

import SvgIcon from "@/components/SvgIcon/src/SvgIcon.vue"; // svg组件

const svgRequire = require.context("@/assets/icons/svg", false, /.svg$/);
svgRequire.keys().forEach(svgIcon => {
  svgRequire(svgIcon);
});

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

mian.js引入require文件

import Vue from "vue";

requireSvg(Vue);

Vue3

svg-sprite-loader 是一个为 Webpack 设计的 loader,用于将 SVG 图标转换为 SVG 精灵。由于 Vite 使用 Rollup 作为其内部打包工具,因此不能直接使用 svg-sprite-loader,需要用vite-plugin-svg-icons来实现

引入vite-plugin-svg-icons

npm install vite-plugin-svg-icons -D

创建SvgIcon.vue文件

<template>
  <svg aria-hidden="true" :style="getStyle">
    <title>{{ title }}</title>
    <use :xlink:href="symbolId" />
  </svg>
</template>

<script setup lang="ts">
  import { computed } from 'vue';

  const props = defineProps({
    name: {
      type: String,
      required: true,
    },
    size: {
      type: [Number, String],
      default: '16',
    },
    width: {
      type: [Number, String],
    },
    height: {
      type: [Number, String],
    },
    title: {
      type: [Number, String],
      default: '',
    },
    color: {
      type: String,
      default: 'none', // 默认为元素本身颜色
    },
  });

  /*
   * 某些图标可能需要保持特定的宽高比,就可以单独设置宽度和高度(例如100*200,但svg只能等比放大缩小,
     图标显示尺寸还是以小的值为准,相当于页面占位100*200,图表本身大小还是100*100,然后y轴居中的效果
   * */
  const getStyle = computed(() => {
    const width = props.width ?? props.size;
    const height = props.height ?? props.size;
    return {
      width: `${width.toString().replace('px', '')}px`,
      height: `${height.toString().replace('px', '')}px`,
      color: props.color,
    };
  });

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

vite.config.js配置

import path from 'path';
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons';  
/**/
plugins: [
    createSvgIconsPlugin({
      iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')], // icon存放的目录
      symbolId: 'icon-[name]', // symbol的id
      inject: 'body-last', // 插入的位置
      customDomId: '__svg__icons__dom__', // svg的id
    }),
  ],

main.ts引入

import 'virtual:svg-icons-register'; // 如果报错没有 fast-glob包, 安装命令 npm install fast-glob -D即可
import SvgIcon from "@/components/SvgIcon/SvgIcon.vue";
const app = createApp(App);
app.component('svg-icon',SvgIcon)

注意

当发现修改svg文件后某些部位颜色没有发生改变时,将svg文件里对应部位自带的fill和stroke属性值修改为currentColor即可,例如

stroke="currentColor" 或 fill="currentColor"