likes
comments
collection
share

开发日记(04) - iconfont 挂了,项目内的图标怎么办?

作者站长头像
站长
· 阅读数 302

📌 0x1 问题

iconfont 应该是挂了有 1-2 两个月了,不管是因为什么原因,肯定会有一大堆的项目有一阵子图标出不来。

作为开发者以来就一直有个感觉,那就是在线服务都不可靠。项目中第三方服务越多,更多不可控的因素就越多。如果都是在自己的服务器上,至少我可以控制服务启动,关闭。都是在同一时间,而不会出现这种能用,但是又没有完全能用的状态,这比服务挂了还恶心。

Node 创始人新搞的 deno 也支持引入在线的脚本,我看到这段代码第一时间不是竟然还能这样写,给我的第一感觉就是这代码某天可能就挂了,导致整个项目起不来。

import { VERSION } from 'https://deno.land/std/version.ts'
console.log(VERSION)

📌 0x2 需要达到的效果

因为是 uni-app 开发的项目,且需要兼容 app 和 nvue。因此图标只能使用单色字体图标的形式,无法直接使用 svg 的形式。
  • 本地导入,不依赖任何的第三方
  • 支持 weex 的 nvue 界面
  • 兼容 h5 和 app 的显示
  • 组件形式使用
  • (web 也是差不多的思路,这里以 uni-app 为例)

📌 0x3 解决思路

既然在线服务不可靠,那么肯定是使用本地导入方式了。现在的 iconfont 是无法使用,无法上传和下载。看看还有什么办法将 svg 转换到字体图标了。github 上有不少将 svg 转换到 webfont 的库。

我尝试下载了几个测试,发现都存在一个问题,就是我从 MasterGo 导出的 svg 图标使用这些工具进行转换的话,在项目内使用始终是一坨黑色的。猜测是 svg 需要进行一些处理。因为我从 iconfont 下载一个 svg 下来进行转换是 ok。这里不展开说,也不是自己擅长的方向。如果你想了解 iconfont 做了什么可以看看这个

里面讲的比较详细,字体图标处理其实有很大的学问,图标很小,做的事情可不少。

📌 0x4 icomoon svg 处理

这是一个类似于 iconfont 的平台,缺点就是只能本地维护,所有的数据都存在缓存,如果清理了浏览器缓存数据就被清除了。不过这个支持我从设计图直接导出的 svg 进行处理。这里以 MasterGo 进行演示实际上就是获取 svg 图标的过程。

4x1 文件改名

首先让 ui 整理好项目内用到的图标,命名好。可以让我直接导出成为 svg。

开发日记(04) - iconfont 挂了,项目内的图标怎么办?

4x2 上传到 icomoon

拿到导出的 svg 图标,上传到 icomoon。点击 icomoon app 进入 icomoon

开发日记(04) - iconfont 挂了,项目内的图标怎么办?

导入 svg 图标

开发日记(04) - iconfont 挂了,项目内的图标怎么办?

选择从 MasterGo 导出的图标,上传

开发日记(04) - iconfont 挂了,项目内的图标怎么办?

选中所有的图标点击生成字体

开发日记(04) - iconfont 挂了,项目内的图标怎么办?

点击预设设置为 class 选择器,取消支持 ie 8,点击 download 下载字体包

开发日记(04) - iconfont 挂了,项目内的图标怎么办?

4x3 拿到导出的文件

看起来和 iconfont 导出的没啥区别。

开发日记(04) - iconfont 挂了,项目内的图标怎么办?

📌 0x5 图标组件

c-icon-moon.vue

普通的 vue 组件,里面的 #ifdef 写法是 uni-app 的条件编译。为了兼容多个平台需要使用到条件编译。

<template>
  <!-- #ifdef APP-NVUE -->
  <text @click="onClick" class="icomoon" :style="iconStyle">{{ icons[name] }}</text>
  <!-- #endif -->

  <!-- #ifndef APP-NVUE -->
  <text @click="onClick" class="icomoon" :class="name" :style="iconStyle" />
  <!-- #endif -->
</template>

<script>
// #ifdef APP-NVUE
import icons from './icons'
// #endif
import { addUnit } from '@/utils'

export default {
  name: 'CustomIconMoon',
  props: {
    size: {
      type: [Number, String],
      default: 'inherit',
    },
    width: {
      type: [Number, String],
      default: 'auto',
    },
    weight: {
      type: String,
      default: 'normal',
    },
    height: {
      type: [Number, String],
      default: 'auto',
    },
    color: {
      type: String,
      default: '#909399',
    },
    name: {
      type: String,
      required: true,
    },
    rpx: {
      type: Boolean,
      required: false,
      default: false,
    },
    bubble: {
      type: Boolean,
      required: false,
      default: true,
    },
  },
  computed: {
    iconStyle() {
      return {
        fontSize: this.size === 'inherit' ? 'inherit' : addUnit(this.size, this.rpx),
        width: addUnit(this.width, this.rpx),
        height: addUnit(this.height, this.rpx),
        color: this.color,
        'line-height': addUnit(this.height, this.rpx),
        'font-weight': this.weight,
      }
    },
  },
  methods: {
    onClick(e) {
      this.$emit('click')
      if (!this.bubble && e) {
        e.stopPropagation()
      }
    },
  },
  // #ifdef APP-NVUE
  data() {
    return {
      icons: icons,
    }
  },
  // #endif
}
</script>

<style scoped>
/* #ifndef APP-NVUE */
@import './style.css';

/* #endif */

.icomoon {
  font-family: icomoon;
}
</style>

addUnit 方法

// 添加单位,如果有rpx,%,px等单位结尾或者值为auto,直接返回,否则加上rpx单位结尾
export function addUnit(value = 'auto', rpx = false) {
  value = String(value)
  return isNumber(value) ? `${value}${rpx ? 'rpx' : 'px'}` : value
}

/**
 * 验证十进制数字
 */
export function isNumber(value) {
  return /^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(value)
}

icomoon-ttf-base64

为了兼容 nvue 需要将 fonts/icomoon.ttf 文件转换为 base64 写入到该文件

转换网址:https://www.giftofspeed.com/base64-encoder/

export default 'AAEAAAALAIAAAwAw...`

icomoon.woff

icons.js

这里配置 nvue 需要显示的图标名字。

\ue912 类似的字符可以打开 style.css 找到你需要在 nvue 显示的图标名字复制。

/**
 * 这里配置需要在 nvue 显示的图标
 */
export default {
  // 指纹
  'icomoon-fingerprint': '\ue912',
}

nvue-helper

nvue 需要的初始化配置。

import icomoonTtfBase64 from './icomoon-ttf-base64'

/**
 * iconfont 需要用ttf转base64
 * 转换网址:https://www.giftofspeed.com/base64-encoder/
 */
export function onInitNvueFontIcon() {
  const dom = uni.requireNativePlugin('dom')
  dom.addRule('fontFace', {
    fontFamily: 'icomoon',
    src: `url('data:font/truetype;charset=utf-8;base64,${icomoonTtfBase64}')`,
  })
}

style.css

删除不需要的格式化,只留下 src: url('icomoon.woff') format('woff'); 这一段就行。

@font-face {
  font-family: icomoon;
  font-style: normal;
  font-weight: normal;
  font-display: block;
  src: url('icomoon.woff') format('woff');
}

.icomoon {
  font-family: icomoon !important;

  /* Better Font Rendering =========== */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-style: normal;
  font-variant: normal;
  font-weight: normal;
  line-height: 1;
  text-transform: none;
}

.icomoon-add::before {
  content: '\e900';
}

/* ... */

📌 0x6 使用

vue 界面

直接参考 组件使用示例 就可以。

Nvue 界面

nvue 界面使用需要导入字体文件,全局只需要导入一次就行了

App.vue

<script>
// #ifdef APP-NVUE
import { onInitNvueFontIcon } from '@/components/c-icon-moon/nvue-helper'
// #endif

export default {
  onLaunch() {
    // eslint-disable-next-line no-console
    console.log('App Launch')
    
    /**
     * Nvue 启动处理
     */
    // #ifdef APP-NVUE
    onInitNvueFontIcon()
    // #endif
  },
  onShow() {
    // eslint-disable-next-line no-console
    console.log('App Show')
  },
  onHide() {
    // eslint-disable-next-line no-console
    console.log('App Hide')
  },
}
</script>

组件使用示例

其实就是 vue 组件的使用了。这里贴一个示例。

<c-icon-moon size="60" name="icomoon-fingerprint" color="red" />

显示效果

开发日记(04) - iconfont 挂了,项目内的图标怎么办?

📌 iconfont 正名

这里为 iconfont 正名一下,先看下网友的情绪 https://github.com/thx/iconfont-plus/issues

开发日记(04) - iconfont 挂了,项目内的图标怎么办?

阿里是大,但不是什么部门都大,内部是有预算分配的,人家是企业,不是慈善机构。从使用 iconfont 这个平台以来一直都是白嫖,准确来说好像没有付费项目。

再来看看今天用到的 icomoon 平台订阅费用,当然是举个例子,有多少公司愿意在 icon 上有这个预算的呢?

开发日记(04) - iconfont 挂了,项目内的图标怎么办?

评论区留给大家。

📔 开发日记系列

只记录些平时开发觉得有用的东西,有问题请务必斧正,拜托了 🙏🙏🙏
  1. 开发日记(01) - uni-app 使用等宽字体对其数字显示
  2. 开发日记(02) - js 异步任务队列
  3. 开发日记(03) - uni-app 打包为 app
  4. 开发日记(04) - iconfont 挂了,项目内的图标怎么办?

关于我

SunSeekerX,

全栈开发、区块链开发、移动端开发、前后端开发、NodeJS 开发、小程序、uni-app 开发、等

喜欢探讨技术实现方案和细节,完美主义者,见不得 bug

Github:https://github.com/SunSeekerX

个人博客:https://yoouu.cn/

个人在线笔记:https://doc.yoouu.cn/