在Vue中使用SVG Sprite整合svg icon

1,731 阅读1分钟

项目中使用图标最方便的方法是使用iconfont,使用方法参考iconfont的下载文件。

但如果想要自定义一些图标(例如团队内部ui绘制的svg图标),sprite技术则是更好的方式。

本文将梳理一下在Vue项目中,如何结合vue-cli和svg-sprite-loader实现svg icon的整合和引入。

核心是以下4步:

  • webpack配置svg-sprite-loader

  • svg图标文件自动导入(批量import)

  • 建立自定义svg-icon组件

  • 引入组件使用

webpack配置svg-sprite-loader

1. 安装svg-sprite-loader

npm install -D svg-sprite-loader

2. 配置

作为icon的svg和作为普通图片的svg使用不同的loader

// vue.config.js
const path = require('path')
const resolve = dir => path.join(__dirname, dir)
module.exports = {
  // ... order options
  chainWebpack(config) {
    // 配置svg规则排除icons目录中svg文件处理
    config.module
      .rule('svg')
      .exclude.add(resolve('src/assets/icons'))
      .end()

    // 新增icons规则,设置svg-sprite-loader处理icons目录中的svg
    config.module
      .rule('icons')
      .test(/\.svg$/)
      .include.add(resolve('src/assets/icons'))
      .end()
      .use('svg-sprite-loader')
      .loader('svg-sprite-loader')
      .options({ symbolId: 'icon-[name]' })
      .end()
  },
}

svg文件自动导入

// 建立一个icons.js实现svg文件的批量导入
// 这里建立在utils下 @/utils/icons.js
const requireAll =
  requireContext => requireContext.keys().map(requireContext)
const req = require.context('../assets/icons', false, /\.svg$/)
requireAll(req)
// main.js
import '@/utils/icons.js'

建立自定义icon组件

这里要注意svg颜色问题,如果你的svg文件里本身有fill属性填充,那么css样式的fill属性则不会生效。所以想要使用css来控制svg的颜色,需要把svg文件的fill属性填充取消。

// SvgIcon.vue
<template>
  <svg
   :class="classes"
   :style="styles"
   aria-hidden="true"
   v-on="$listeners"
  >
    <use :xlink:href="iconName"></use>
  </svg>
</template>

<script>
export default {
  name: 'SvgIcon',
  props: {
    iconClass: {
      type: String,
      required: true,
    },
    color: { // 设置颜色
      type: String,
      required: true,
    },
    size: [Number, String], // 自定义尺寸
    className: {
      type: String,
      default: '',
    },
  },
  computed: {
    iconName() {
      return `#icon-${this.iconClass}`
    },
    classes() {
      return this.className ? `svg-icon ${this.className}` : 'svg-icon'
    },
    styles() {
      let style = {}
      if (typeof this.size === 'number') {
        style.width = `${this.size}px`
        style.height = `${this.size}px`
      } else {
        style.width = this.size
        style.height = this.size
      }
      if (this.color) {
        style.fill = this.color
      }
      return style
    },
  },
}
</script>

<style scoped>
.svg-icon {
  width: 1em;
  height: 1em;
  fill: transparent; // 默认不填充
  overflow: hidden;
}
</style>

可以将SvgIcon注册成全局组件

// main.js
import SvgIcon from '@/components/SvgIcon'
Vue.component('svg-icon', SvgIcon)

引入

// component.vue
<template>
  <div>
    <svg-icon iconClass='your svg file name' color="#fff" size="30" />    
  </div>
</template>