首页 > 技术文章 > vue-cli3引入svg图标全过程以及遇到的坑

jianghaijun4031 2019-09-22 16:11 原文

一、讲原理svg-sprite,和css-sprite有点像,就是先把所有的svg图放页面上,但是不现实,用的时候去取。

这个时候去MDN补一下知识。Symbol这个不是es6里的那个新增的数据类型,而是SVG中的一个标签https://developer.mozilla.org/zh-CN/docs/Web/SVG/Element/symbol

官方说法:

symbol元素用来定义一个图形模板对象,它可以用一个<use>元素实例化。symbol元素对图形的作用是在同一文档中多次使用,添加结构和语义。结构丰富的文档可以更生动地呈现出来,类似讲演稿或盲文,从而提升了可访问性。注意,一个symbol元素本身是不呈现的。只有symbol元素的实例(亦即,一个引用了symbol的 <use>元素)才能呈现。

联系一下我刚才说的svg-sprite你就知道了,就是我们要把我们所有svg的单个放到这个标签里,然后再起个ID,用的时候一找这个id就出来。非常完美。原理还有更有深度的东西可以自己百度去吧。

那我们要用时候不能挨个写标签,挨个放进去吧,那就太麻烦了,所有用这个插件svg-sprite-loader,我们只需要准备下svg图,然后起个好记的名字。然后svg是美工给你的,所以你只需要改名字。。为了就是这个,要不谁用他

npm install svg-sprite-loader --save-dev

接下来在vue.config.js里加这些东西。上代码

先找到这个位置

这个位置是配置webpack额外配置的,因为vue-cli3已经帮你配置好了,但是对于这需求各种变的年代。不改是不可能的,还不如在webpack里配置呢。。吐槽一下。接下来就把下边这些代码放进去

const svgRule = config.module.rule('svg');
    // 清除已有的所有 loader。
    // 如果你不这样做,接下来的 loader 会附加在该规则现有的 loader 之后。
    svgRule.uses.clear();
    svgRule
      .test(/\.svg$/)
      .include.add(path.resolve(__dirname, './src/icons/svg'))
      .end()
      .use('svg-sprite-loader')
      .loader('svg-sprite-loader')
      .options({
        symbolId: 'icon-[name]'
      });
    const fileRule = config.module.rule('file');
    fileRule.uses.clear();
    fileRule
      .test(/\.svg$/)
      .exclude.add(path.resolve(__dirname, './src/icons/svg'))
      .end()
      .use('file-loader')
      .loader('file-loader');

你不要纳闷,为啥配置这svg的规则又配置了下file,这个就是坑。

来先看一下package.json

这个开发依赖也没有file-loader啊,配置他干嘛。。我就为了这个都哭,看着没有,实际上有,就是这些vue/cli的某个的以来还是用的是file-loader所以你要是不配置的话,就会有两个东西去处理你的svg,文件。他会告诉你需要你一个loader,实际上你有俩。

此时按我这个配置就可以了。为了证明有,你看看这个。。

然后自己写个组件。,再用webpack的

require.context方法把那些svg导入进来。这个方法作用就是把所有的svg亿import形式引入进来。

看代码

先看组件

<template>
  <svg :class="svgClass" xmlns="http://www.w3.org/2000/svg">
    <use :xlink:href="iconName" xmlns:xlink="http://www.w3.org/1999/xlink" />
  </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>

用的时候就是icon-class里的就是svg你开始的命名,别整中文啊。后边这个class-name就是你自定义的class,要设置大小记得font-size可别width,height啥的。。那就很尴尬了

<svg-icon icon-class="copy" class-name="size"></svg-icon>

接下来就是如何引入的svg的进入页面的

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

// register globally
Vue.component('svg-icon', SvgIcon);
const req = require.context('./svg', false, /\.svg$/);
const requireAll = requireContext => requireContext.keys().map(requireContext);
requireAll(req);

先把组件全局注册,然后引入组件;

如果看不懂就直接百度require.context然后你就懂了。

这个时候再去main.js里引入就好了。(别忘了这一步)

import './icons'; // icon

你就可以用了,而且是页面各个角度的用。你要看一下dom结构有没有这个。

有你就大胆用吧,啥毛病没有,没有的话,是不是你svg名字给写错了。其他都没错了还是不显示就去检查这个webpack的配置吧和控制台的错误输出。其他就只有碰到了才清楚。

现在最新版给的方法是这个(先别急着用)

1.在对应vue项目里添加插件

vue add svg-sprite

2.再执行:

npm install svgo svgo-loader --save-dev

这里开发以来会增加一个vue-cli-svg-sprite和svgo和svgo-loader

因为svgo可以整理svg的某些东西,去掉或者增加,反正是可以批量处理他们,以方便我们使用。他会给我们自动生成一个已经写好的组件  到时候你引入这个组件就可以了。我的情况就是没找到原因就是一直不显示还不报错。so,我抛弃了他,使用了上边的方法,实际上vue-cli-svg-sprite的依赖也是svg-sprite-loader,没准问题也是file-loader的事,应该是我的某些配置问题。如果有大神知道原因,希望你告诉我一下吧。最近没空去探寻真理,实现了先用。

 

 

推荐阅读