iconfont的使用和封装

2,149 阅读3分钟

前言

  • 雪碧图: 新增一个图标,都需要改动原始图片,还可能不小心出错影响到前面定位好的图片,维护困难
  • iconfont: 解决了上述痛点

iconfont的三种方式使用

unicode

  • 优势
    • 兼容性最好,支持ie6+
    • 支持按字体的方式去动态调整图标大小,颜色等等
  • 劣势
    • 不支持多色图标
    • 在不同的设备浏览器字体的渲染会略有差别,在不同的浏览器或系统中对文字的渲染不同,其显示的位置和大小可能会受到font-size、line-height、word-spacing等CSS属性的影响,而且这种影响调整起来较为困难
    • 书写不直观,语意不明确。光看这个unicode你完全不知道它代表的是什么意思
  • 使用方式
    <i class="iconfont">&#xe604;</i>
    

font-class

symbol: svg-icon 使用形式

创建 icon-component 组件

icon组件: components/SvgIcon

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

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

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

使用该组件

import IconSvg from '@/components/SvgIcon'

// 全局注册SvgIcon
Vue.component('svg-icon', SvgIcon)
// 在代码中使用
<svg-icon icon-class="password" />
  • 缺点
    1. 它是一段用js来生成svg的代码,所有图标 icon 都很不直观
    2. 做不到按需加载,不能根据我们使用了那些 svg 动态的生成 svg-sprite
    3. 自定义性差,通常导出的svg包含大量的无用信息,例如编辑器源信息、注释等
    4. 添加不友善,自定义的svg图标,只能将其也上传到 iconfont 和原有的图标放在一个项目库中,之后再重新下载,很繁琐

优化

svg-sprite

  • 使用 svg-sprite解决上述问题: svg-sprite-loader 将加载的 svg 图片拼接成雪碧图,放到页面中,其它地方通过<use>复用

  • 问题: vue-cli默认情况下会使用 url-loader 对svg进行处理,引入svg-sprite-loader 会引发一些冲突

  • 解决方法: 放到指定文件夹下面,使用include和exclude解决

    {
      test: /\.svg$/,
      loader: 'svg-sprite-loader',
      // include
      include: [resolve('src/icons')],
      options: {
        symbolId: 'icon-[name]'
      }
    },
    {
      test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
      loader: 'url-loader',
      // exclude
      exclude: [resolve('src/icons')],
      options: {
        limit: 10000,
        name: utils.assetsPath('img/[name].[hash:7].[ext]')
      }
    }
    
  • 使用图标

    // 单个导入
    import '@/src/icons/qq.svg;
    
    // 批量导入
    const requireAll = requireContext => requireContext.keys().map(requireContext)
    const req = require.context('./svg', false, /\.svg$/)
    requireAll(req)
    
    // symbolId中加了前缀'icon-',为了与阿里图标名称保持一致
    <svg><use xlink:href="#icon-qq" /></svg>
    

vue中的优化(svg-sprite)

安装: npm install svg-sprite-loader -D

  • vue.config.js: 改完重启一下项目

    const { resolve } = require('path');
    
    module.exports = {
      chainWebpack: config => {
        config.module
          .rule('svg')
          .exclude.add(resolve('src/icons'))
          .end()
        config.module
          .rule('icons')
          .test(/\.svg$/)
          .include.add(resolve('src/icons'))
          .end()
          .use('svg-sprite-loader')
          .loader('svg-sprite-loader')
          .options({
            symbolId: 'icon-[name]'
          })
          .end()
      },
    };
    
  • src/icons/index.js

    import Vue from 'vue'
    import SvgIcon from '../components/SvgIcon'
    
    // 全局注册icon组件
    Vue.component('svg-icon', SvgIcon)
    
    // 批量导入src/icons/svg目录下的所有.svg文件
    const req = require.context('./svg', false, /\.svg$/)
    const requireAll = requireContext => requireContext.keys().map(requireContext)
    requireAll(req)
    
  • 使用组件

    <svg-icon icon-class="qq" />
    
  • 参考: svg-sprite-loader 使用教程-作者赵永盛

svg压缩工具: svgo

  • 问题: 虽然 iconfont 网站导出的 svg 内容已经算蛮精简的了,但你会发现其实还是与很多无用的信息,造成了不必要的冗余。连 iconfont 网站导出的 svg 都这样,更不用说那些设计师导出的svg了
  • 解决方法: 好在 svg-sprite-loader也考虑到了这点,它目前只会获取 svg 中 path 的内容,而其它的信息一概不会获取 残留问题: 在 path 中产生的冗余信息svg-sprite-loader就不会处理了,如注释什么的
  • 进一步解决方法: svgo
    • 安装: npm install -g svgo
    • 使用
      • 单文件压缩: svgo 压缩前.svg -o 压缩后.svg
      • 多文件压缩: svgo -f 文件夹(压缩前) -o 文件夹(压缩后)

参考