在vue项目中优雅的使用Svg

32,763 阅读3分钟

github demo: github地址 如果对您有用,请顺手给个star...

闲聊背景

本文主要以vue-cli3搭建的项目为例,来聊一下如何在项目中更优雅的使用svg

众所周知,vue-cli3已经推出很长一段时间了,大家可以感受一下vue-cli3带来的零配置体验。But,也相应带来了一些弊端,就是如果需要修改默认的loader时,会比较麻烦。

好了,上正题,建议看此文章之前先去看一下张鑫旭大神的未来必热:SVG Sprite技术介绍,那么我们接下来主要使用的就是上文中提到的svguse,先上一张vue-cli3搭建的项目的目录,可以看到根目录下只保留了public/以及src/,可以说非常干净,大家可以自己创建一个。

src/components/下创建SvgIcon组件

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

<script>
export default {
  name: 'SvgIcon',
  props: {
    iconClass: {
      type: String,
      required: true,
    },
    className: {
      type: String,
      default: '',
    },
  },
  computed: {
    iconName () {
      return `#icon-${this.iconClass}`
    },
    svgClass () {
      if (this.className) {
        return 'svg-icon ' + this.className
      } else {
        return 'svg-icon'
      }
    },
  },
}
</script>

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

src/下创建一个icons目录,目录结构如下:

svg目录主要用于存放svg文件,来看一下index.js的内容,功能就是把组件注册到全局,方便使用:

import Vue from 'vue'
import SvgIcon from '@/components/SvgIcon' // svg组件

// 注册到全局
Vue.component('svg-icon', SvgIcon)

const requireAll = requireContext => requireContext.keys().map(requireContext)
const req = require.context('./svg', false, /\.svg$/)
requireAll(req)

当然,如果你有自己的想法或需求,可以单独引入,无需非要注册到全局。

main.js中引入

这一步就没什么好说的了,如果需要注册到全局,需要在入口文件中引入。

好了,接下来是最重要的一步:

修改默认的loader:

大家可以去vue-cli3官网去查看具体教程,这里我只说需要修改的loader以及具体的代码实现。

首先需要注意的是,通过vue-cli3构建的项目可以初始化进行很多选择,我构建的目录更多的是以*.config.js的形式存在的。

在根目录下创建一个名为vue.config.js文件,接下来的操作都和它有关,先来看一下它完整的代码:

const path = require('path')

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

module.exports = {
  chainWebpack: config => {
    config.plugin('define').tap(args => {
      const argv = process.argv
      const icourt = argv[argv.indexOf('--icourt-mode') + 1]

      args[0]['process.env'].MODE = `"${icourt}"`

      return args
    })
    // svg rule loader
    const svgRule = config.module.rule('svg') // 找到svg-loader
    svgRule.uses.clear() // 清除已有的loader, 如果不这样做会添加在此loader之后
    svgRule.exclude.add(/node_modules/) // 正则匹配排除node_modules目录
    svgRule // 添加svg新的loader处理
      .test(/\.svg$/)
      .use('svg-sprite-loader')
      .loader('svg-sprite-loader')
      .options({
        symbolId: 'icon-[name]',
      })

    // 修改images loader 添加svg处理
    const imagesRule = config.module.rule('images')
    imagesRule.exclude.add(resolve('src/icons'))
    config.module
      .rule('images')
      .test(/\.(png|jpe?g|gif|svg)(\?.*)?$/)
  },
  configureWebpack: {
    devServer: {
      open: true,
      // https: true,
      proxy: {
        '/user': {
          target: 'https://devadminschool.icourt.cc',
        },
        '/live': {
          target: 'https://devadminschool.icourt.cc',
        },
      },
    },
  },
}

大家忽略无关紧要的代码,重点从svg rule loader注释开始,其实注释已经比较详细了,就是获取默认的loader并进行相关的修改,主要有svg-loaderimages-loader,从vue-cli3基础loader中可以找到这两个loader的默认配置。

// 默认的svg loader...
webpackConfig.module
  .rule('svg')
    .test(/\.(svg)(\?.*)?$/)
    .use('file-loader')
      .loader('file-loader')
      .options({
        name: genAssetSubPath('img')
      })
      
// 默认的images loader...
webpackConfig.module
      .rule('images')
        .test(/\.(png|jpe?g|gif|webp)(\?.*)?$/)
        .use('url-loader')
          .loader('url-loader')
          .options(genUrlLoaderOptions('img'))

对比我一开始的代码可以看出,我把默认的svg loader配置中使用的file-loader改为了svg-sprite-loader,并排除了node_modules,把默认的images-loader配置添加了svg,并排除了src/icons目录。

如何使用?

  • 可以把设计大大给的svg 或者从iconfont官网下载开源的icon的svg格式,复制到src/icons/svg目录下;
  • 点击svg查看源码,修改fill属性, fill="currentColor",或者fill="",如果无此属性,就不用管,这样做是可以让外部控制icon的颜色,或随父元素的color;
  • 注意svg命名和SvgIcon命名一致,看一下最终使用:
    这里就会使用src/icons/svg/go-back.svg文件。

总结:

以上讲的比较糙,奈何文字功底是硬伤,最后附上github demo 代码示例: 此项目也可以当做项目初始架构,内置了vue-router、vuex等。

本文以vue-cli3创建的项目为例,之前的项目可以直接去手动修改对应的loader即可。

github地址 如果对您有用,请顺手给个star...

本文是在掘金上发布的第一篇帖子,新人入驻,还请各位前辈多关怀...