使用svg 雪碧图实现一个Icon组件

808 阅读2分钟

介绍

目前我们实现css图标主要是通过svg实现,svg图标相比于图片图标有以下优点:

  1. SVG是矢量图形文件,无限放大不失真,显示清晰, 可以适应不同的尺寸和分辨率。
  2. 可以用CSS样式来自由定义图标颜色,比如颜色/尺寸等效果。
  3. 使用SMIL、CSS或者是javascript可以制作充满灵性的交互动画和滤镜效果。
  4. 由于SVG也是一种XML节点的文件,所以可以使用gzip的方式把文件压缩到很小

svg雪碧图

SVG Sprite 类似于CSS中的Sprite技术。将图标图形整合在一起,实际呈现的时候准确显示特定图标。svg实现雪碧图主要是靠和标签

symbol和use

symbol元素用来定义一个图形模板对象。symbol元素本身是不显示的,只有使用元素引用后才会进行渲染。

定义了元素之后,可以使用元素来对它进行无限次实例化展示。通过定义元素xlink:href属性来指定要展示的图标,xlink:href属性值为要展示元素的id。

例子如下:

<svg>
<!-- symbol definition  NEVER draw -->
<symbol id="sym01" viewBox="0 0 150 110">
  <circle cx="50" cy="50" r="40" stroke-width="8" stroke="red" fill="red"/>
  <circle cx="90" cy="60" r="40" stroke-width="8" stroke="green" fill="white"/>
</symbol>

<!-- actual drawing by "use" element -->
<use xlink:href="#sym01"
     x="0" y="0" width="100" height="50"/>
<use xlink:href="#sym01"
     x="0" y="50" width="75" height="38"/>
<use xlink:href="#sym01"
     x="0" y="100" width="50" height="25"/>
</svg>

将上述代码放入到html中没有使用元素引用时,页面是空白的,使用元素引用之后效果如下:

使用

svg-sprite-loader生成svg雪碧图

svg-sprite-loader是用来生成svg 雪碧图的webpack loader, 它可以把所有引入的svg文件自动生成symbol标签,在需要使用图标的地方使用元素引用就可以了

使用步骤:

  1. 安装svg-sprite-loader
npm install svg-sprite-loader -D

或 yarn add svg-sprite-loader -D
  1. 配置webpack loader
{
    test: /.svg$/,
    loader: 'svg-sprite-loader',
    include: 
    options: {
      symbolId: '[name]' // 使用文件名作为symbolId
    }
}

在vue-cli3中的配置方式

    config.module
      .rule('svg-sprite')
      .test(/icons/.+(.svg)(?.*)?$/)
      .use('svg-sprite')
      .loader('svg-sprite-loader')
      .options({
        symbolId: '[name]'
      })

创建一个公用的icon组件

  1. 创建icon组件
<template>
  <svg class="icon" :width="size" :height="size">
    <use :xlink:href="iconName" />
  </svg>
</template>
export default {
  name: 'ICON',
  props: {
    name: {
        type: String,
        required: true
    },
    size: {
        type: Number,
        default: 16
    }
  },
  computed: {
    iconName() {
      return `#${this.name}`
    }
  }
}
</script>

使用

import Icon from 'com/icon/index.vue'
import './close.svg'

<icon name="close"/>
  1. 引入所有的svg文件

在每次使用一个图标的时候import 一个svg文件是非常麻烦的事情, 我们可以通过webpack的require.context 生成context module 动态引入icon,这样每次添加一个svg文件时就不用手动添加该svg的import了

require.context接受3个参数:1.文件夹 2.是否使用子文件 3.文件匹配的正则

require.context会返回一个函数,该函数有keys,id,resolve()属性

  • keys()方法返回的该模块可以处理的模块的数组,就是满足该参数的模块, 类似于['./close.svg', './open.svg']
  • resolve()返回请求的module的id
  • id是该context module的id
require.context(directory, useSubdirectories = false, regExp = /^.///)
// requires and returns all modules that match
const requireAll = requireContext => requireContext.keys().map(requireContext);

// import all svg
const req = require.context('./assets/svg', true, /.svg$/);
requireAll(req);
  1. 全局注册ICON组件

入口文件index.js

import Icon from 'com/icon/index.vue'
Vue.component('Icon', Icon)
  1. 在自己的组件中使用
 <icon name="close" size="12" />