背景
通过微信小程序 wx.loadFontFace 加载第三方字体:
wx.loadFontFace({
family: 'Bitstream Vera Serif Bold',
source: 'url("https://sungd.github.io/Pacifico.ttf")',
success: console.log
})
但是这样每次进入小程序都会请求字体,浪费资源(特别字体文件还不小),所以打算直接存,下次直接读本地字体文件
解决方式
graph LR
A[Start] --> B{本地有字体};
B -- Yes --> C[显示字体];
B -- No --> D[请求网络字体] --> E[字体存储];
D ---> C;
C ----> F[End]
这里最大的问题就是,如何加载本地字体
官方文档并没有说能支持本地字体文件,于是实测吧:
- 模拟器可以正常加载显示 ✅
- 真机(iOS 测的)不行 ❌
那既然直接字体文件不行,类比 CSS,base64 呢?CSS 不仅支持在线 url,也能使用 base64,咱直接转读文件,转成 base64 给 wx.loadFontFace 试一下:
- 模拟器可以 ✅
- 真机也可以 ✅
于是基于下载字体、缓存文件、文件转 base64 字体,简单撸了个 behavior:
仅参考,文件我存在微信云服务里,普通 cdn 文件的需要修改下载 api
export default Behavior({
methods: {
_downloadFont (fileID, filePath, fontFamily) {
wx.cloud.downloadFile({
fileID, // cloud 文件 id
success: res => {
wx.getFileSystemManager().saveFile({ // 下载成功后保存到本地
tempFilePath: res.tempFilePath,
filePath,
success: res => {
// 加载字体
this._loadFontFace(fontFamily, res.savedFilePath)
}
})
}
})
},
// 加载文件字体转 base64,load
_loadFontFace (fontFamily, filePath) {
wx.getFileSystemManager().readFile({ //读文件
filePath, // 本地文件地址
encoding: 'base64',
success: res => {
wx.loadFontFace({
global: true, // 是否全局生效
family: fontFamily, // 字体名称
source: `url("data:font/woff2;charset=utf-8;base64,${res.data}")`,
})
}
})
// wx.loadFontFace({
// family: fontFamily,
// source: `url("${filePath}")`, // 不支持本地路径
// })
},
// fileID: 云文件 id
// filename: 存储文件路径
// fontFamily: css 中字体的 family
loadCloudFontFace (fileID, filename, fontFamily) {
const filePath = `${wx.env.USER_DATA_PATH}/${filename}`
wx.getFileSystemManager().access({
path: filePath,
success: () => {
this._loadFontFace(fontFamily, filePath)
},
fail: () => {
this._downloadFont(fileID, filePath, fontFamily)
}
})
}
},
})
使用:
Page({
behaviors: [loadFontBehavior],
onLoad() {
this.loadCloudFontFace('cloud://space-xxxxx/font/Font.otf', 'Font.otf', 'FontName')
}
})
.text {
font-family: "FontName";
}
其他
代码没有考虑一些边界 case,仅供参考思路