前言
- 雪碧图: 新增一个图标,都需要改动原始图片,还可能不小心出错影响到前面定位好的图片,维护困难
- iconfont: 解决了上述痛点
iconfont的三种方式使用
unicode
- 优势
- 兼容性最好,支持ie6+
- 支持按字体的方式去动态调整图标大小,颜色等等
- 劣势
- 不支持多色图标
- 在不同的设备浏览器字体的渲染会略有差别,在不同的浏览器或系统中对文字的渲染不同,其显示的位置和大小可能会受到font-size、line-height、word-spacing等CSS属性的影响,而且这种影响调整起来较为困难
- 书写不直观,语意不明确。光看这个unicode你完全不知道它代表的是什么意思
- 使用方式
<i class="iconfont"></i>
font-class
- 优势
- 兼容性良好,支持ie8+
- 相比于unicode语意明确,书写更直观。可以很容易分辨这个icon是什么
- 使用方式
<i class="iconfont icon-xxx"></i> - 如在vue项目中使用icon 阿里图标库中的小图标-作者廖客
symbol: svg-icon 使用形式
- 优势
- 支持多色图标了,不再受单色限制
- 支持像字体那样通过font-size,color来调整样式
- 支持 ie9+
- 可利用CSS实现动画
- 减少HTTP请求
- 矢量,缩放不失真
- 可以很精细的控制SVG图标的每一部分
- 使用方式
<svg class="svg-icon" aria-hidden="true"> <use xlink:href="#icon-xxx"></use> </svg> - 如vue-cli通过symbol引用阿里iconfont图标-作者不想做设计的前端不是一个好的攻城狮(需要多引入一个iconfont.js)
创建 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" />
- 缺点
- 它是一段用js来生成svg的代码,所有图标 icon 都很不直观
- 做不到按需加载,不能根据我们使用了那些 svg 动态的生成 svg-sprite
- 自定义性差,通常导出的svg包含大量的无用信息,例如编辑器源信息、注释等
- 添加不友善,自定义的svg图标,只能将其也上传到 iconfont 和原有的图标放在一个项目库中,之后再重新下载,很繁琐
优化
svg-sprite
-
使用 svg-sprite解决上述问题: svg-sprite-loader 将加载的 svg 图片拼接成雪碧图,放到页面中,其它地方通过
<use>复用- svg-sprite-loader
- 安装: npm install svg-sprite-loader -D
-
问题: 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压缩工具: 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 文件夹(压缩后)
参考
- 花裤衩: 手摸手,带你优雅的使用 icon
- 廖客: 在vue项目中使用icon 阿里图标库中的小图标
- 不想做设计的前端不是一个好的攻城狮: vue-cli通过symbol引用阿里iconfont图标
- 赵永盛: svg-sprite-loader 使用教程