白羽
白羽
  • 发布:2019-09-19 21:31
  • 更新:2023-11-25 18:00
  • 阅读:10908

【分享】在uniapp的nvue和subNVue中添加本地自定义字体/字体图标的方法

分类:nvue

使用uniapp做开发,时不时会遇到困难。遇到困难时,可以在Dcloud社区和QQ群提问。但Dcloud官方分配于解答开发者疑问的力量远远不足,大多数提问根本不会得到任何回复。我是个暴脾气,很多时候气得捶足顿胸。但那又怎样呢,不回复就是不回复。

以前,我对这个问题只会抱怨。后来,我想通了:自己对社区并没有太多贡献,凭什么社区无偿为你解答问题?如果每个人都愿意花一点时间,主动在社区发布一些经验分享,或者回复一些他人遇到而自己已有解决方案的问题,那么社区的质量就会提升,下次遇到问题时,在社区搜索答案就更容易命中有效答案了。

所以,从现在开始,以后但凡有些许有价值的经验总结,哪怕价值很小很小,我都会发布到社区。虽然个人的能力非常有限,解决不了很大的问题,只能从小处着手,但兴许对未来的某一个人有用呢?


以下是正文

nvue和subnvue引入自定义自体/自定义图标,不能用CSS方法,而只能用week所规定的方法。具体做法是,在nvue或subnvue页面内,引入如下js代码(uni-app编译模式下,可放置于onLoad函数内;week编译模式下,可放置于beforeCreate函数内。貌似也可以直接放置于“export default {...}”之前)。

const domModule = weex.requireModule('dom')  
domModule.addRule('fontFace', {  
    'fontFamily': "iconfont2",  
    'src': "url('http://at.alicdn.com/t/font_1469606063_76593.ttf')"  
});

其中:

  • @fontFace 协议名称,不可修改。
  • @fontFamily font-family的名称。
  • @src 字体地址,url('') 是保留字段,其参数如下:
    1. http. 从HTTP请求加载, e.g. url('http://at.alicdn.com/t/font_1469606063_76593.ttf')
    2. https. 从HTTPS请求加载, e.g. url('https://at.alicdn.com/t/font_1469606063_76593.ttf')
    3. local, Android ONLY. 从assets目录读取, e.g. url('local://foo.ttf'), foo.ttf 是文件名在你的assets目录中.
    4. file. 从本地文件读取, e.g. url('file://storage/emulated/0/Android/data/com.alibaba.weex/cache/http:__at.alicdn.com_t_font_1469606063_76593.ttf')
    5. data. 从base64读取, e.g. url('data:font/truetype;charset=utf-8;base64,AAEAAAALAIAAAwAwR1NVQrD ....'), 上述data字段不全。

问题

问题的难点在于:src的正确写法。http和https写法要求联网加载,如果断网就无法显示,其用户体验肯定不好。local写法只有Android能够采用,iOS无法采用,兼容性差。那么,就只剩下file写法和data写法可用了。

但问题在于,file的正确写法是怎样的?我试了N种办法,都失败了。最后只能采用data写法:先百度“ttf转base64”,把ttf文件上传到网上的“ttf转base64”网页,将生成的data字段复制到上述data字段即可。但问题来了:(1)不放心那些未知网站,担心转码形成的base64有个别字节错误;(2)大段的base64数据影响代码的美观,且会干扰HX的变量提示功能;(3)修改ttf文件(如增删改图标)需要重新转码生成新的base64……总之,很不方便。

理想的写法,还是file写法,url('file://storage/...');

作为小白,在缺乏直接资料的情况下,根本不知道file正确写法是怎样的。而且这种非核心小问题,在Dcloud和QQ群上提问,是不可能得到回复的。在陆续花费了几天的时间后,终于解决了。

具体办法

(1)将自己的ttf文件(如iconfont.ttf),放置于static目录下
(2)在nvue或subnve的js中加入如下代码:

const domModule = weex.requireModule('dom')  
domModule.addRule('fontFace', {  
    'fontFamily': "iconfont2",  
    'src': 'url("'+"file:/" + plus.io.convertLocalFileSystemURL("_www/static/iconfont.ttf")+'")'  
});

(3)在需要引入iconfont.ttf中的自定义字体/图标的页面元素的css中添加font-family: iconfont2。这一步千万别忘了。
(4)引用字体。在html中,采用"&#n位十进制unicode码"格式引用自定义字符/字体图标,例如“&#57349”;在js中,采用“\u四位十六进制unicode码”格式,例如“\uE005”;而在css中,则采用“\四位十六进制unicode”格式,例如“\E005”。

注意

  1. plus.io.convertLocalFileSystemURL()函数可以把本地相对路径转换为本地绝对路径。
  2. 代码中的“file:/”只有一条斜杠,而是不两条。因为,plus.io.convertLocalFileSystemURL()函数获得的本地绝对路径,已经自带了一条斜杠。
  3. fontFamily的值,即iconfont2可以任意取。但iconfont.ttf文件内部的字体的名称必须足够特殊、不与系统注册的其他字体的名称冲突。
  4. “font-family: iconfont2;”必须直接放置于具体引用自定义字体的<text>标签的css中,而不能放置于<text>标签的父/祖标签的css中,否则自定义定体将不生效。例如:
    <view class="mytext1">  
    <text class="mytext2">&#57349{{text}}</text>  
    </view>
    data() {  
     return {  
        text: '\uE005'  
     }  
    }
    .mytext1 {  
        font-family: iconfont2;  
    }  
    .mytext2 {  
        font-family: iconfont2;  
    }

在上述代码中,“.mytext1”由于没有直接作用于<text>标签,因而无效;“.mytext2”由于直接作用于<text>标签,所以有效。

补充:发现了一个巨坑:按照上述方法引用的自定义字体,仅在开发阶段(真机模拟时)有效,云打包之后仍然不能工作。
最新实测有效的建议:
在开发阶段,可采用 'src': 'url("'+"file:/" + plus.io.convertLocalFileSystemURL("_www/static/iconfont.ttf")+'")'这种写法,能在真机模拟时工作;开发完成后,打包时,可采用url('data:font/truetype;charset=utf-8;base64,AAEAAAALAIAAAwAwR1NVQrD ....')这种写法,在真机运行和打包后都能够工作。在开发阶段,也可采用url('data:font/truetype;charset=utf-8;base64,AAEAAAALAIAAAwAwR1NVQrD ....')这种写法,但不建议,原因在前文说过:干扰代码开发且不便于修改ttf文件。
另,附一个ttf文件转base64的网站
https://www.zhangxinxu.com/sp/base64.html
生成的base64,复制到HX新页面后,先将头部字符修改为data:font/truetype;charset=utf-8;base64,再复制到代码中。

27 关注 分享
小张没有名字 9***@qq.com 1***@qq.com 水灵退散 大图APP Doray 氵氵海 9***@qq.com 雨夜敬清秋 1***@qq.com 2***@qq.com HunkZhu 1***@163.com bzwlegend 独角兽 f***@easier.cn liub1934 一抱一个胖猪猪 1***@qq.com zzdev Kytrun rysnone Simons hws007 9***@qq.com 石滔滔 wq在忙碌

要回复文章请先登录注册

XIANXU

XIANXU

字体图标现正只作用于text标签上
2022-02-15 09:12
人生不设限

人生不设限

跟着补充一点url中不加引号也不行,必须加引号
```javascript
const domModule = uni.requireNativePlugin('dom')
domModule.addRule('fontFace', {
'fontFamily': "wlicon",
'src': "url('data:font/truetype;charset=utf-8;base64,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AAADYALhAAwAHAAxAEYAXABxAAABMj4BNC4BIg4BFB4BByIOARUUFjMhMjY1NC4BIyUzMjY9ATMyNj0BNCYrASIGHQEUFhMjNTQmKwEiBh0BFBY7ATI2PQE0JgEjIgYdARQWOwEVFBY7ATI2PQE0JiMTIyIGHQEjIgYdARQWOwEyNj0BNCYCASI6IiI6RDoiIjoFMlUyCAYBowYIMlUy/ognBgpqBgkJBqEGCgqnagoGJwYKCgahBgoKAfqgBwoKB2kKBicGCgoHAScGCmoGCgoGoQYKCgGLIjlFOiEhOkU5IhsyVTIGBwcGMlUysAkHagkHJgcJCQegBwn+RmoHCQoGoAcJCQcmBwkCegkHJgcJagYKCgagBwn+AAoGagkHJgcJCQegBgoABQAA/8kDgQM2AAgAFAAwAEcAVwAAARQPASc2NzUzJxUHDgEPASc+ATc1Nx4BFSM0LgEiDgEdARQGDwEnPgE/ATQ+ATMyFjceAR0BFA8BJzY/ATQuAQYHJzY3NhcWBQ4BBxUUDwEnNjc9ATQ2NwLVUQpLTAVVqgECOzUKQjA3AsIeIFUiO0Y7IjIvCT4mKgIBOWI6Kk+XNjoZBlMZAwFZmKlEPUxeXFlc/kYcHgEhB0oZAyspASuynRIqh5w+gKoRV6VGDDY8kE26bR5PKiI7IyM7IoBHhDQKOydkNo06YjkgWjaNTIBtaBcWXWCZVJFMDzM9PBERGxygJVYuYEg/DSsrMgxWQXszAAAAAAAAEgDeAAEAAAAAAAAAEwAAAAEAAAAAAAEACAATAAEAAAAAAAIABwAbAAEAAAAAAAMACAAiAAEAAAAAAAQACAAqAAEAAAAAAAUACwAyAAEAAAAAAAYACAA9AAEAAAAAAAoAKwBFAAEAAAAAAAsAEwBwAAMAAQQJAAAAJgCDAAMAAQQJAAEAEACpAAMAAQQJAAIADgC5AAMAAQQJAAMAEADHAAMAAQQJAAQAEADXAAMAAQQJAAUAFgDnAAMAAQQJAAYAEAD9AAMAAQQJAAoAVgENAAMAAQQJAAsAJgFjQ3JlYXRlZCBieSBpY29uZm9udGljb25mb250UmVndWxhcmljb25mb250aWNvbmZvbnRWZXJzaW9uIDEuMGljb25mb250R2VuZXJhdGVkIGJ5IHN2ZzJ0dGYgZnJvbSBGb250ZWxsbyBwcm9qZWN0Lmh0dHA6Ly9mb250ZWxsby5jb20AQwByAGUAYQB0AGUAZAAgAGIAeQAgAGkAYwBvAG4AZgBvAG4AdABpAGMAbwBuAGYAbwBuAHQAUgBlAGcAdQBsAGEAcgBpAGMAbwBuAGYAbwBuAHQAaQBjAG8AbgBmAG8AbgB0AFYAZQByAHMAaQBvAG4AIAAxAC4AMABpAGMAbwBuAGYAbwBuAHQARwBlAG4AZQByAGEAdABlAGQAIABiAHkAIABzAHYAZwAyAHQAdABmACAAZgByAG8AbQAgAEYAbwBuAHQAZQBsAGwAbwAgAHAAcgBvAGoAZQBjAHQALgBoAHQAdABwADoALwAvAGYAbwBuAHQAZQBsAGwAbwAuAGMAbwBtAAACAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoBAgEDAQQBBQEGAQcBCAEJAQoBCwADY2hlGXhpbmdtaW5neW9uZ2h1bWluZ25pY2hlbmcEbWltYQdzaHVheGluB2RpYW5uYW8NZ2VyZW56aG9uZ3hpbgZ0dWljaHUNcmVubGlhbnNoaWJpZQh6aGl3ZW4yeAAA')"
})
```
2021-10-19 10:29
zzdev

zzdev

补充一个奇怪的点吧,**可能跟引号有点关系**,我用的base64的文件格式,如果我写的是单引号包双引号,显示就是问号
```
src: 'url("data:font/truetype;charset=utf-8;base64,AAA...")'
```
但如果改成反引号包单引号,显示就正常
```
src: `url('data:font/truetype;charset=utf-8;base64,AAA...')`
```
2021-10-18 11:41
Firer

Firer

< text style="fontFamily:iconfont">&# xe67d;</ text> fontFamily:iconfont必须写在标签上
2021-05-13 11:30
x***@126.com

x***@126.com

只有官方的可以用,我在Alibaba ICON上自定义的字体,按照楼主提供的网站转化后使用还是不行啊
2021-03-05 10:09
x***@126.com

x***@126.com

为什么我的不行呢?
2021-03-05 10:08
luispater

luispater

找了很多资料都不靠谱,不过受你的启发,我使用了一个plus函数的方式,不过nvue也只有在有plus的方式,将代码放在App.vue的onLaunch下,fontFamily全局加载一次就可以了,代码如下:
```
onLaunch: function () {
const importNetworkIconFont = function () {
const domModule = weex.requireModule('dom');
domModule.addRule('fontFace', {
'fontFamily': "iconfont",
'src': "url('https://at.alicdn.com/t/font_2301509_vtjfkk6ep2h.ttf')"
});
}
const reader = new plus.io.FileReader();
reader.onloadend = function (e) {
if (e.target.result) {
const domModule = weex.requireModule('dom')
domModule.addRule('fontFace', {
'fontFamily': "iconfont",
'src': "url('" + "data:font/truetype;charset=utf-8;base64" + e.target.result.substr(e.target.result.indexOf(",")) + "')"
});
} else {
importNetworkIconFont();
}
};
reader.onerror = function (e) {
console.log("没有读取到iconfont.ttf文件")
importNetworkIconFont();
}
reader.readAsDataURL(plus.io.convertLocalFileSystemURL("static/iconfont.ttf"));
}
```
更新的时候,只要把iconfont.ttf换成新的就可以了,也不用关心是正式还是测试环境,问题解决,非常感谢作者的帮助!
2020-12-31 00:14
999

999

感谢 楼主分享
2020-11-11 18:58
1***@qq.com

1***@qq.com

感谢 楼主分享
2020-07-03 14:51
1***@qq.com

1***@qq.com

在使用阿里图标的时候 记得把阿里生成的base64 data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAqEAAsAAA 里面的 data:application/x-font-woff2 改成 data:font/truetype;
2020-07-03 14:50