优雅的使用icon之svg

3,322 阅读1分钟

使用 svg-sprite


接下来我们就要自己来制作 svg-sprite 了。这里要使用到 svg-sprite-loader 这个神器了, 它是一个 webpack loader ,可以将多个 svg 打包成 svg-sprite

安装依赖:svg-sprite-loader

npm i svg-sprite-loader -D

下载图标,将所有svg存入src/icons/svg中


修改vue.config.js


使用vue inspect --rules可以查看所有规则定义,我们使用vue inspect --rule svg查看,我们发现vue-cli默认情况下会使用 url-loader 对svg进行处理。

//默认`vue-cli` 对svg做的处理,正则匹配后缀名为.svg的文件,匹配成功之后使用 url-loader 进行处理。
 {
    test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
    loader: 'url-loader',
    options: {
      limit: 10000,
      name: utils.assetsPath('img/[name].[hash:7].[ext]')
    }
}

为避免冲突我们修改如下规则配置:

chainWebpack(config) {
    // 修改svg规则排除icons目录中svg文件
    config.module
      .rule("svg")
      .exclude.add(resolve("src/icons"))
      .end();
    // 新增icons规则,设置svg-sprite-loader处理icons目录中的svg
    config.module
      .rule("icons")
      .test(/\.svg$/)
      .include.add(resolve("src/icons"))
      .end()
      .use("svg-sprite-loader")
      .loader("svg-sprite-loader")
      .options({
        symbolId: "icon-[name]"
      });

图标自动导入


我们发现一个个import svg太麻烦了,我们就要使用到 webpack 的 require.context。很多人对于 require.context可能比较陌生,直白的解释就是

require.context("./svg", false, /.svg$/); 这行代码就会去 svg 文件夹(不包含子目录)下面的找所有文件名以 .svg 结尾的文件能被 require 的文件。 更直白的说就是 我们可以通过正则匹配引入相应的文件模块。

require.context有三个参数:

  • directory:说明需要检索的目录
  • useSubdirectories:是否检索子目录
  • regExp: 匹配文件的正则表达式
//icons/index.js
const req = require.context("./svg", false, /\.svg$/);

req.keys().map(req);

创建Svgicon组件


在./components/SvgIcon.vue

<template>
  <svg :class="svgClass" aria-hidden="true" v-on="$listeners">
    <use :xlink:href="iconName" />
  </svg>
</template>

<script>
export default {
  props: {
    iconClass: {
      type: String,
      required: true
    },
    className: {
      type: String,
      default: ""
    }
  },
  data() {
    return {};
  },

  components: {},

  computed: {
    iconName() {
      return `#icon-${this.iconClass}`;
    },
    svgClass() {
      if (this.className) {
        return "svg-icon " + this.className;
      } else {
        return "svg-icon";
      }
    }
  },

  methods: {}
};
</script>
<style lang="scss" scoped>
.svg-icon {
  width: 1em;
  height: 1em;
  vertical-align: -0.15em;
  fill: currentColor;
  overflow: hidden;
}
</style>

注册全局组件


在./icons/index.js

import Vue from "vue";
import SvgIcon from "@/components/SvgIcon";
// 注册全局组件
Vue.component("svg-icon", SvgIcon);

调用


<svg-icon iconClass='vx' />
<svg-icon iconClass='qq' />