在前端项目中,会用到很多小图标,这些图标很小,但是数量会很多,比如导航、按钮等等,其中很多在不同项目还会重复用到。

使用方式
直接使用图片
最简单的图片使用方式,就是UI给出的图片,在代码中使用img标签,或者background属性来引用。
引用的图片可以维护在项目本地,也可以放到cdn。
雪碧图
直接使用图片,会有很多并发的网络请求,因此可以讲这些小图标合并成一张大图,通过background-position定位来展示不同的图标。这样多个请求合并成一个,优化了性能,但是使用和维护起来麻烦。
关于雪碧图的维护,我们可以通过插件在编译阶段解决,自动生成雪碧图,并且生成css文件,开发的时候,按照文件名的class命名去引用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| var path = require('path'); var SpritesmithPlugin = require('webpack-spritesmith'); module.exports = { module: { rules: [ {test: /\.styl$/, use: [ 'style-loader', 'css-loader', 'stylus-loader' ]}, {test: /\.png$/, use: [ 'file-loader?name=i/[hash].[ext]' ]} ] }, resolve: { modules: ["node_modules", "spritesmith-generated"] }, plugins: [ new SpritesmithPlugin({ src: { cwd: path.resolve(__dirname, 'src/ico'), glob: '*.png' }, target: { image: path.resolve(__dirname, 'src/spritesmith-generated/sprite.png'), css: path.resolve(__dirname, 'src/spritesmith-generated/sprite.styl') }, apiOptions: { cssImageRef: "~sprite.png" } }) ] };
|
1 2 3 4 5 6 7
| @import '~sprite.styl' .close-button sprite($close) .open-button sprite($open)
|
转base64
相对于雪碧图,在编译阶段将小图标直接转成base64更加方便。虽然图片转成base64体积会增大,不过只是一些小图标的话可以忽略。
1 2 3 4 5 6 7 8 9 10 11 12 13
| { test: /.(jpg|jpeg|webp|png|svg|gif|woff|woff2|eot|ttf|otf)$/, exclude: /(node_modules|bower_components)/, use: [ { loader: 'url-loader', options: { limit: 8192, name: '[path][name].[ext]', }, }, ], }
|
iconfont
雪碧图和base64解决了请求多的问题,但是还是以图片的形式维护,如果遇到图标的颜色发生变化,就需要UI给出新的图片,如果需要动态改变图片颜色,就只能切换图片来实现。对于图标的使用,iconfont是一个更好的方案,将图标转成一个字体文件,然后在使用的时候,就可以像字体一样去修改颜色和大小。
首先需要UI提供svg格式的图标,然后通过iconmoon或者阿里巴巴图标资源库(https://www.iconfont.cn/)上传,生产字体文件,然后下载到项目使用。

下载后,放到项目目录,可以新建一个iconfont文件夹,然后引入iconfont.css。项目中就可以用class名来使用字体图标了。这里一般是本地维护字体文件,当有新的图标时,不能直接使用,而是要重新生成字体文件,在项目中更新,再使用新的class,维护麻烦一些。但是使用阿里巴巴图标资源库,便于一个公司或业务线集中维护图标,方便多个不同项目使用。
另外iconfont除了用class方式外,更推荐symbol方式使用,也就是svg的形式,可以支持多色图标,但是直接写起来复杂一些。
用svgtofont(https://www.npmjs.com/package/svgtofont)这个包,也可以在项目本地维护svg图片,本地生成字体图标。
小程序中也可以使用iconfont,但是需要将iconfont的字体文件转换成base64。阿里巴巴图标资源库可以直接生成base64格式的字体文件。也可以将ttf文件在这个网站进行转换:https://transfonter.org/。这里我基于svgtofont开发了一个svg转base64格式iconfont的库:https://www.npmjs.com/package/miniapp-svg2iconfont,方便小程序项目本地维护图标。
svg-sprite-loader
这个其实就是iconfont的symbol方式,不过是在项目本地管理svg图片。然后在vue和react项目中,可以通过封装组件,简化svg的写法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| const path = require('path')
function resolve (dir) { return path.join(__dirname, dir) }
module.exports = defineConfig({ ...,
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() }, ...,
})
|
1 2 3 4 5 6 7 8 9 10
| import SvgIcon from '@/components/SvgIcon'
export default (vue) => { vue.component('svg-icon', SvgIcon) const req = require.context('./svg', false, /\.svg$/) const requireAll = requireContext => requireContext.keys().map(requireContext) requireAll(req) }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| <template> <div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" /> <svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners"> <use :xlink:href="iconName" /> </svg> </template>
<script>
import { isExternal } from '@/utils/methods.js'
export default { name: 'SvgIcon', props: { iconClass: { type: String, required: true }, className: { type: String, default: '' } }, computed: { isExternal () { return isExternal(this.iconClass) }, iconName () { return `#icon-${this.iconClass}` }, svgClass () { if (this.className) { return 'svg-icon ' + this.className } else { return 'svg-icon' } }, styleExternalIcon () { return { mask: `url(${this.iconClass}) no-repeat 50% 50%`, '-webkit-mask': `url(${this.iconClass}) no-repeat 50% 50%` } } } } </script>
<style scoped> .svg-icon { width: 1em; height: 1em; vertical-align: -0.15em; fill: currentColor; overflow: hidden; }
.svg-external-icon { background-color: currentColor; mask-size: cover !important; display: inline-block; } </style>
|
这样既有了svg的优点,可以像iconfont方案一样修改大小颜色,并且svg支持的属性更丰富。再一个svg本地管理的话,更便于随时维护,并且svg本身就是代码形式,开发可以编辑微调。
小程序暂不支持svg标签的使用,只能把svg文件在image标签传入使用,因此这个方法在小程序不适用。
维护方式对比
|
本地图片 |
cdn图片 |
阿里巴巴图标资源库 |
| 优点 |
维护方便 |
代码体积小 |
项目间共用 |
| 缺点 |
每个项目独立维护 |
维护麻烦 |
增加单个图片维护麻烦 |
综合分析