前言: 本文主要记录一下,从vue-element-admin框架中,学习到使用icon的经验。希望以后,可以运用到自己的项目中。
一、前端icon的发展史
??????在远古时代,大部分图表都是用img来实现的。这样会使一个页面的请求资源中,图片img占了大部分,为了优化有了image sprite就是所谓的雪碧图,就是将多个图片合成一个图片,然后利用css的background-position定位显示不同的icon图标。 ??????font库,后来渐渐地一个项目里,几乎不会使用任何本地的图片了,而使用一些font库来实现页面图标。如常见的Font Awesome 。 ??????iconfont----一个阿里做的开源图库,他们的图标数量还是很惊人的,还有各式各样的小图标,还支持自定义创建图标库。
二、iconfont 三种使用姿势
添加链接描述 ??????(1)unicode ??????①最开始,我们使用unicode的格式,它主要的特点优势是:
- 兼容性最好,支持ie6+;
- 支持按字体的方式去动态调整图标大小,颜色等等;
②劣势: - 不支持多色图标;
- 在不同的设备浏览器字体的渲染会略有差别,在不同的浏览器或系统中对文字的渲染不同,其显示的位置和大小可能会受到font-size、line-height、word-spacing等CSS属性的影响,而且这种影响调整起来较为困难。
??????(2)font-class ??????与unicode使用方式相比,具有以下特点:
- 兼容性良好,支持ie8+;
- 相比于unicode语意明确,书写更直观。可以很容易分辨这个icon是什么。
??????(3)symbol ??????随着某某游览器逐渐淡出历史舞台,svg-icon使用形式慢慢成为主流和推荐的方法。推荐文章:未来必热:SVG Sprite技术介绍 。PS:本文主要记录一下,使用symbol的方法。
- 支持多色图标,不再受单色限制;
- 支持像字体那样通过font-size,color来调整样式;
- 支持ie9+;
- 可利用CSS实现动画;
- 减少HTTP请求;
- 矢量,缩放不失真;
- 可以很精细的控制SVG图标的每一部分。
??????使用方法:第一步:考不项目下面生成的symbol代码:
引入 ./iconfont.js
??????第二步:加入通用css代码(引入一次就行):
<style type="text/css">
.icon {
width: 1em; height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
</style>
??????第三步:挑选相应图标并获取类名,应用于页面:
<svg class="icon" aria-hidden="true">
<use xlink:href="#icon-xxx"></use>
</svg>
??????使用svg-icon的好处是,我再也不用发送woff|eot|ttf这些很多个字体库请求了,我所有的svg都可以内联在html内。 ??????还有一个,就是svg是一个真正的矢量,不管你再怎么的放缩它都不会失真模糊,而且svg可以控制的属性也更加的丰富,也能做出更加生动和复杂的图标。
三、创建icon-component组件
??????我们有了图标,接下来就是如何在自己的项目中优雅的使用它了。下面基于vue的实例:
<template>
<svg class="svg-icon" aria-hidden="true">
<use :xlink:href="iconName"></use>
</svg>
</template>
<script>
export default {
name: 'icon-svg',
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/IconSvg'
Vue.component('icon-svg', IconSvg)
<icon-svg icon-class="password" />
??????就这样简单封装了一个Icon-svg组件,我们就可以简单优雅的在自己的vue项目之中,使用图标了。
四、进一步改造
??????目前,还有一个缺点,就是现在所有的svg-sprite都是通过iconfont的iconfont.js生成的。
- 首先,它是一段用js来生成svg的代码,所有图标icon都很不直观;
- 其次,它也做不到按需加载,不能根据我们使用了哪些svg动态生成的svg-sprite ;
- 自定义性差,通常导出的svg包含大量的无用信息,例如编辑器源信息、注释等。通常包含其他一些不会影响渲染结果或可以移除的内容;
- 添加不友善,如果有一些自定义的svg图标,该如何和原有的iconfont整合到一起呢?目前,只能将其也上传到iconfont和原有的图标放在一个项目库中,之后再重新下载,很繁琐。
使用svg-sprite ??????接下来,我们就哟啊自己来制作svg-sprite了。这里要使用到svg-sprite-loader这个工具了,它是一个webpack loader,可以将多个svg打包成svg-sprite 。 ??????接下来介绍如何在vue-cli的基础上进行改造,加入svg-sprite-loader。 ??????我们发现vue-cli默认情况下,会使用url-loader对svg进行处理,会将它放在**/img目录下,所以这时候我们引入svg-sprite-loader**会引发一些冲突。
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
}
??????解决方案有两种,最简单的就是你可以将test的svg去掉,这样就不会对svg做处理了,当然这样做是很不友善的。
- 你不能保证你所有的svg都是用来当做icon的,有些真的可能只是用来当做资源的;
- 不能确保你使用的一些第三方类库会使用到svg。
??????所以,最安全合理的做法是使用webpack的exclude和include,让svg-sprite-loader只处理你指定文件夹下面的svg,url-loader只处理除此文件夹之外的所有svg,这样就完美解决了之前冲突的问题。代码如下: ??????这样配置好了,只要引入了svg之后填写类名就可以了:
import '@/src/icons/qq.svg;
<svg><use xlink:href="#qq" /></svg>
??????单这样,还是非常的不优雅,那如果项目中有一百个icon,难不成要手动一个个引入嘛? ??????自动导入 ??????首先,我们创建一个专门放置图标icon的文件夹如:@/src/icons,将所有icon放在这个文件夹下。之后,我们就要使用到webpack的require.context 。很多人对于require.context可能比较陌生,直白的解释就是:
require.context("./test", false, /.test.js$/); 这行代码就会去 test 文件夹(不包含子目录)下面的找所有文件名以 .test.js 结尾的文件能被 require 的文件。 更直白的说就是 我们可以通过正则匹配引入相应的文件模块。
??????require.context有三个参数:
- directory:说明需要检索的目录;
- useSubdirectories:是否检索子目录;
- regExp:匹配文件的正则表达式。
??????了解这些之后,我们就可以这样写来自动引入@/src/icon下面所有的图标了:
const requireAll = requireContext => requireContext.keys().map(requireContext)
const req = require.context('./svg', false, /\.svg$/)
requireAll(req)
??????之后,我们增删改图标直接文件夹下对应的图标就好了,什么都不用管,就会自动生成svg symbol了。 ??????更进一步优化自己的svg ??????首先,我们来看一下从阿里iconfont网站上导出的svg长什么样? ??????是的,虽然iconfont网站导出的svg内容,已经算蛮精简的了,但你会发现其实还是与很多无用的信息,造成了不必要的冗余。好在svg-sprite-loader也考虑到了这点,它目前只会获取svg中path的内容,而其他的信息一概不会获取。生成的svg如下图: ??????但任何你在path中产生的冗余信息,它就不会做处理了。如注释什么的: ??????这时候,我们就要使用另一个很好用的东西了----svgo 。 ??????它支持几十种优化项,非常的强大,8K+的star也足以说明问题。 ??????svgo是什么?
它是一个用于优化SVG文件的Node.js工具。
??????为什么要用svgo? ??????因为我们从网上下载或者导出的SVG文件中包含着大量无用的信息,例如编辑源信息,注释以及其它一些不会影响渲染效果但可以去除的信息,这时候可以通过svgo插件,将这些无用的信息进行去除,从而达到优化的效果。该svgo具有基于插件的体系结构,因此几乎每个优化都是一个单独的插件。 参考博客: 手摸手,带你优雅的使用 icon https://juejin.cn/post/6844903517564436493
|