uni-app实现自定义图标组件

705 阅读4分钟

我正在参与掘金创作者训练营第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组件出场了,接下来聊聊怎么封装一个好用的图标组件吧。

组件实现

目录结构

image.png

组件具体实现

/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字体图标库做示例,其他字体图标库同理。

点击项目设置

image.png

项目设置

修改"FontClass/Symbol 前缀"项为"e-",修改"Font Family"为"e-iconfont",这里的名称只是示例,可以根据需求自定义名称。字体格式选择WOFF,具有比较好的兼容性,使用其他格式也可以,我看uView的示例使用的是WOFF2,我觉得WOFF更稳妥吧,大小也不会大很多,是个比较综合的考虑。重点的要勾选Base64, 在微信小程序是不支持字体文件引入的,需要使用Base64的方式。如下图:

image.png

下载项目至本地

image.png

引入字体文件

复制"iconfont.css"至项目,放在根目录的 static(其他文件也行,不过推荐放在这个文件夹下) 文件夹下

image.png

最终效果

image.png

使用字体文件

uni-app因为是跨端项目,所以就会有一些兼容问题出现,平常我们可能会在main.js里面引入字体文件,如下:

// 正常引入
import './static/iconfont.css'

// 异步引入,避免文件过大,影响首次加载,提高性能
import('./static/iconfont.css')

但是在uni-app打包成App时,这种使用方式会提示报错,打包失败,所以需要在App.vuestyle中引入

image.png

小结

通过对于不同自定义图标的实现方式对比,找出不足之处,并提供了对应的解决方式,这样一个简单又能提高开发效率的自定义Icon组件就实现了,也许还有挺多的不足之处,大家可以自行对其进行扩展。

这里只是抛砖引玉,大家可以共同探讨更好的解决方式,有问题也欢迎指出。