封装 Icon 的 Vue 组件实例
前言
本文主要介绍使用阿里矢量图标库iconfont.cn,在 Vue 项目中对 icon 进行组件封装,使得图标库便于后续开发使用。
关于 icon-font 的 4 种使用方法
官网介绍在代码中的应用有 4 种方式https://www.iconfont.cn/help/detail?spm=a313x.7781069.1998910419.16&helptype=code
- 直接下载单个图标文件,在代码中引入,可以是 png、svg 等格式,这种方式适用于图标临时使用、或者只是单独使用的场景,好处是可以自选颜色,方便快捷;
- Unicode 引用,类似字体文件的引入,好处是兼容性强,支持 ie6 及以上版本浏览器,由于是字体,所以可以用
font-size / color去改变大小和颜色,但不支持多色图标,具体使用代码可以参考上面的链接; - font-class 引用,由于 Unicode 方式使用不够直观,不知道具体引用的是哪个图标,说白了就是不够语义化,本质和 Unicode 引用是一样的,兼容 ie8 及以上;
- symbol 引用,传闻是未来主流方式,那就用这种方式来建立 Vue 组件吧。
symbol 方式创建全局图标组件
IconFont 官方建议使用线上版本,即在线引入 svg,但这样做会造成每次增删改图标时,生成的 JS 链接都会改变,所以每次都得改引用的 url,而我一般会把生成的 JS 代码复制到本地,然后通过本地全局import,步骤如下;
- 建立
icon(folder) -> index.js(jsFile) && iconfont.js(jsFile),复制生成的代码到iconfont.js里,index.js里引入; - 建立公共组件
icon-svg.vue,代码如下,#icon-xxxx是按照 IconFont 规范组合成的超链接名字,其他的 props 可以根据需要增删。
<!-- usage -->
<!-- <icon-svg name="xxxx" /> -->
<template>
<svg
:class="getClassName"
:width="width"
:height="height"
aria-hidden="true">
<use :xlink:href="getName"></use>
</svg>
</template>
<script>
export default {
name: 'icon-svg',
props: {
name: {
type: String,
required: true
},
className: {
type: String
},
width: {
type: String
},
height: {
type: String
}
},
computed: {
getName () {
return `#icon-${this.name}`
},
getClassName () {
return [
'icon-svg',
`icon-svg__${this.name}`,
this.className && /\S/.test(this.className) ? `${this.className}` : ''
]
}
}
}
</script>
<style>
.icon-svg {
width: 1em;
height: 1em;
fill: currentColor;
overflow: hidden;
}
</style>
- 在 index.js 里引入 Vue 和 IconSvg 组件,全局注册后使用。
这种方式有一个很烦的地方就是如果图标频繁更换,那就需要一直改动icon-font.js文件,大佬们想出了svg-sprite雪碧图的方式,来看看怎么整的。
svg-sprite
- 在本地建立
src -> icons(folder)保存所有用到的 svg 图标,安装svg-sprite-loader,它是一个webpack-loader,可以将多个 svg 打包成一个svg-sprite,和雪碧图思想一样的,先画好所有的 svg,用 symbol 标示每个图标,这样同一页面中遇到相同的 svg 就不用重复再绘制了; - 对组件进行改造,首先由于很多项目脚手架自带有
url-loader插件,没有的可以跳过,也会对后缀名为 svg 的文件进行处理,而我们要对 svg 图标进行处理,所以更改build -> webpack.base.conf.js文件,利用 webpack 的 include 和 exclude,只针对 icon 的 svg 做处理,代码如下,完成这步之后,可以用import '@/src/icons/qq.svg;这段代码引入icon,用<svg><use xlink:href="#qq" /></svg>来使用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
test: /\.svg$/,
loader: 'svg-sprite-loader',
include: [resolve('src/icons')]
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
exclude: [resolve('src/icons')],
options: {
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
}
- 那这样一个个去引入图标还是很麻烦,所以想到了用webpack的
require.context,这个方法可以找到特定目录下的特定文件,再批量引入,后面会写一篇blog来介绍这个方法,在index.js里写代码如下,路径需要自己修改,最后获取svg文件名称那一步,也需要根据实际的命名规则去修改:
1
2
3
4
5
6
7
8
const svgFiles = require.context('src/icons', true, /\.svg$/)
const iconList = svgFiles.keys().map(item => svgFiles(item))
export default {
// 获取图标icon-(*).svg名称列表, 例如[shouye, xitong, zhedie, ...]
getNameList () {
return iconList.map(item => item.default.id.split('-')[1])
}
}
- 最后我们实现了一个脱离IconFont的组件,但是事实上使用方法是类似的,摆脱了需要频繁增删svg文件而产生的多文件导入的烦恼。
结语
这种方法更适合不怎么用fontawesome的人,并且不用兼容低版本浏览器的,大概思路就是创建svg-sprite,对<svg><use></use></svg>这样一个模板进行封装,批量引入svg文件,最后全局注册即可使用。