我正在参与掘金创作者训练营第5期,点击了解活动详情
前言
在日常项目开发中,图标的使用是必不可免的,目前前端UI框架都会提供Icon组件,同时内置了一套相应的图标,但这并不能完全满足我们的需求,我们需要使用公司内部提供的自定义图标,有些UI框架会提供自定义图标方式,集成还是比较容易的,但是有些没有提供,或者提供了,但是使用方式比较麻烦。这篇文章虽然是以uni-app
为示例,但思想对于前端项目都是一致的。
自定义图标方式
对于图标的使用方式,字体图标和svg图标是比较常用的方式,UI框架也大多采用这两种方式。
项目集成图标方式
- 以类名为基础实现不同icon以及icon样式的控制
- 基于UI框架提供的Icon组件集成自定义图标
- 自定义Icon组件
以类名为基础实现不同icon控制
<i class="icon icon-card size-16"></i>
这种使用方式应该是比较少人的选择,使用起来比较繁琐,不灵活,内部也需要定义大量的类名来满足需求
基于UI框架提供的Icon组件集成自定义图标
这里以uni-app
做的比较好的UI组件库uView
作为举例,在uView2.0
因为在nvue
下暂时无法解决自定义图标的问题,所以是不支持自定义图标的,在uView1.0
支持这个特性,配置文档可以自行查看,最终的使用方式如下,需要添加Icon
的前缀配置,这样子使用也是比较麻烦的。
<u-icon name="backspace" custom-prefix="custom-icon" size="30" color="#888888"></u-icon>
自定义Icon组件
对于上面两种方式的分析,在某些情况下,要么不支持自定义图标,要么使用起来太过于繁琐,开发效率比较低,这时候自定义Icon
组件出场了,接下来聊聊怎么封装一个好用的图标组件吧。
组件实现
目录结构
组件具体实现
/src/components/e-icon/e-icon.vue
<template>
<text class="e-icon" :class="_classNames" :style="[_style]"></text>
</template>
<script>
export default {
name: "EIcon",
props: {
// 图标类型
type: {
type: String,
default: "",
},
// 图标样式
styleSheet: {
type: Object,
default: () => ({}),
},
// 图标尺寸
size: {
type: [Number, String],
default: 32,
},
color: {
type: String,
default: "",
},
},
computed: {
rule() {
// 读取Icon规则,并进行正则判断
const rules = uni.EIcon.rules || [];
for (let i = 0; i < rules.length; i++) {
const rule = rules[i];
const test = new RegExp(rule.test);
if (test.exec(this.type)) {
return rule;
}
}
},
// 组合类名
_classNames() {
const { color, rule, type } = this;
const classNames = [];
classNames.push(rule?.fontFamily || "");
classNames.push(type);
return classNames.join(" ");
},
// 组合样式
_style() {
const { styleSheet, size, color } = this;
const style = {
...styleSheet,
};
let _size = size + "";
if (!_size.endsWith("rpx")) {
_size += "rpx";
}
style.fontSize = _size;
style.color = color;
return style;
},
},
};
</script>
组件注册方法实现
/src/components/e-icon/index.js
import EIcon from "./e-icon.vue";
// EIcon组件注册方法实现,并赋值Icon规则
EIcon.install = function (Vue, options) {
uni.EIcon = {
rules: options,
};
Vue.component(EIcon.name, EIcon);
};
export default EIcon;
组件注册
/src/main.js
这边为什么需要外部来提供Icon规则配置,不能内置吗,答案是可以。但是这么做的话,就会陷入和UI组件库的自定义icon图标的困境,因为你没办法知道当前使用的图标是对应哪一套图标库,所以需要传一个类似与这种的custom-prefix="custom-icon"
图标前缀,这违背了我们自定义图标组件的初衷。虽然我们这边需要去写icon规则配置,但这样子,我们里面就可以自动去匹配对应的图标组件库了。
// 组件引入
import EIcon from "@/components/e-icon";
// 组件注册,并且传入Icon规则
Vue.use(EIcon, [
{
// 配置前缀
test: "^e-.*",
// 配置font-family
fontFamily: "e-iconfont",
},
]);
具体使用
<e-icon type="e-shouye" color="red" size="32"></e-icon>
引入字体文件
上面已经完成了关于Icon组件的具体实现,以及使用方式,还差一步引入字体文件,就算大功告成了,这里以iconfont字体图标库做示例,其他字体图标库同理。
点击项目设置
项目设置
修改"FontClass/Symbol 前缀"项为"e-",修改"Font Family"为"e-iconfont",这里的名称只是示例,可以根据需求自定义名称。字体格式选择WOFF
,具有比较好的兼容性,使用其他格式也可以,我看uView
的示例使用的是WOFF2
,我觉得WOFF
更稳妥吧,大小也不会大很多,是个比较综合的考虑。重点的要勾选Base64
, 在微信小程序是不支持字体文件引入的,需要使用Base64的方式。如下图:
下载项目至本地
引入字体文件
复制"iconfont.css"至项目,放在根目录的 static(其他文件也行,不过推荐放在这个文件夹下) 文件夹下
最终效果
使用字体文件
在uni-app
因为是跨端项目,所以就会有一些兼容问题出现,平常我们可能会在main.js
里面引入字体文件,如下:
// 正常引入
import './static/iconfont.css'
// 异步引入,避免文件过大,影响首次加载,提高性能
import('./static/iconfont.css')
但是在uni-app
打包成App
时,这种使用方式会提示报错,打包失败,所以需要在App.vue
的style
中引入
小结
通过对于不同自定义图标的实现方式对比,找出不足之处,并提供了对应的解决方式,这样一个简单又能提高开发效率的自定义Icon组件就实现了,也许还有挺多的不足之处,大家可以自行对其进行扩展。
这里只是抛砖引玉,大家可以共同探讨更好的解决方式,有问题也欢迎指出。