以接口请求的方式,解决移动端页面中字体文件过大的问题
需求
背景:内容发布系统(想象一下今日头条的文章)面向移动端的文章,被要求使用思源宋体的字(客户付钱买的字体),2个字体文件加起来有30MB。
PS:中文字体发展落后英文字体,最大的一个原因就是字体包太大,第二原因是字太多,所以设计字体的人也少。。。不像英文26个字母,两者不是一个量级的。
方案说明
需要技术: js, nodejs,服务器 一个,nginx
示例地址: 点我预览
github仓库:https://github.com/font-size/node-fontmin-project
核心:通过fontmin切割字体,一个原本十几MB(思源宋体)的字体通过切割基本可以达到几十KB的效果。
方案优势:
- 整套方案由纯js实现,轻量级应用
- 字体文件变成按需加载,量级从MB变成KB,切割后的大小不如一张普通的图
- 对现有项目的页面改动小,对各种类型的项目兼容性好
- 可以批量实现
实现步骤:
- 在服务端新增nodejs接口
- 前端页面新增请求post接口,根据返回的字体文件url,动态设置font-face等页面样式
- 示例如下
可以看到这个字体的size只有短短19.4kb,更令人惊喜的是,他是用接口实现的,也就是说,前端项目可以很方便的兼容。
从0开始架设node服务的步骤
- 起nodejs服务,开发一个js页面
- 下载nodejs安装包,在服务器上(或本地)安装
- 新建一个目录,输入npm init,然后一路确认,生成package.json。
- 接着npm安装依赖 (fontmin,express,body-parser3个依赖包),代码分别是npm i fontmin --save,npm i express–save,npm i body-parser–save
- 开发逻辑代码(开发一个post接口)
- nodejs代码
目录下新建express.js
// const fs = require('fs');
const fontmin = require('./fontmin')// 切割程序,后续会讲
const express = require('express');
const bodyParser = require('body-parser');
// 设置可用字体
const fonts = [{font: 'SourceHanSerifCN-Medium', name: '思源宋体'},{font: 'PangMenZhengDao', name: '庞门正道粗书体'},{font: 'RuiziGongfangMeiheiGBK', name: '锐字工房云字库美黑GBK'},{font: 'RuiziZhenyanti', name: '锐字真言体'},{font: 'YousheBiaotihei', name: '优设标题黑'},{font: 'Zihun116', name: '字魂116号-凤鸣手书'}
]// express 实例
const app = express();// 转化参数设置
app.use(bodyParser.json());app.use(bodyParser.urlencoded({extended:true
}));// post 接口
app.post('/getfontmin', function(request, response){const params = request.bodyconst font = params.fontconst text = params.text// 如果传递的font字体在后台没有就返回400const item = fonts.find(e => e.font === font)if(item) {fontmin(font, text, function(e) {if(e === 'done') {const data = {params: params,headers: request.headers} console.log(data )// 拼接参数 返回请求let back = {url: '/fontmin/font/' + font + '.ttf',font: font}response.send(back);} });} else {response.status(400);response.send('没有请求的字体文件');}
});app.listen(3000);
上述代码内容是用express监听了3000端口,定义了一个getfontmin的post接口,并在response的body返回url和font。
express.js里的getfontmin接口,接受2个参数,分别是文章中的所有文字和所需要的字体类型。
例:前端传的参数为
{text: '爱的飞行日志',font: 'SourceHanSerifCN-Medium'
}
获取到参数后,把这2个参数传递给定义好的fontmin 函数,切割程序。
下面是切割程序代码 fontmin.js,用到了fontmin这个npm包
module.exports = function (font, text, callback) {const Fontmin = require('fontmin')var srcPath = `./fonts/${font}.ttf`; // 字体源文件var destPath = './font'; // 输出路径var text = text || '';// 初始化var fontmin = new Fontmin().src(srcPath) // 输入配置.use(Fontmin.glyph({ // 字型提取插件text: text // 所需文字})).use(Fontmin.ttf2eot()) // eot 转换插件.use(Fontmin.ttf2woff()) // woff 转换插件 .use(Fontmin.ttf2svg()) // svg 转换插件.use(Fontmin.css()) // css 生成插件.dest(destPath); // 输出配置// 执行fontmin.run(function (err, files, stream) {if (err) { // 异常捕捉console.error(err);}// console.log('done'); // 成功return callback('done')});
}
接受text和font作为参数,进行字体切割,可以设置对应文件和输出目录,很好很强大。
- 注意:这里destPath设置为固定路径,在实际项目上一般需要根据页面把切割好的字体文件放到特殊目录。
- 如前端页面是http://www.wangzhan.com/content/20200901/index.jhtml,设置destPath为/content/20200901/font 相信会是一个更好的选择。
在目录下运行node express.js
- 到此为止,服务端里nodejs代码已经全部结束,接下来做前端实现
前端页面实现
比如我有个页面,需要压缩字体。
- 首先开发一个post.js
function fontmin(selectDom, fontDom) {// 获取文字const text = document.querySelector(selectDom).innerText// 字体const font = fontDom// 设置post typeaxios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';// 接口地址axios.post('/getfontmin', {text: text,font: font}).then(function (response) {// 当接口成功返回时,动态给head设置csslet styleDom = document.createElement('style');styleDom.type = 'text/css';const cssText = `@font-face {font-family: "${response.data.font}";src: url("${response.data.url}") format("truetype");}p, h1 {font-family: "${response.data.font}";}`styleDom.appendChild(document.createTextNode(cssText));document.getElementsByTagName('head')[0].appendChild(styleDom)// alert("设置成功")}).catch(function (error) {console.log(error);alert("设置失败")});
}
这段js代码用了axios插件来请求post接口。这个接口即我们之前定的getfontmin接口。
根据接口返回的url和font,用js在页面上加上一个style元素,设置font-face等样式。
- 前端页面 index.html
<!DOCTYPE html>
<html lang="en" >
<head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no,viewport-fit=cover"/>
<style>
h1 {font-size: 60px;
}
p, h1 {text-align: center;font-size: 40px;
}
</style>
</head>
<body><div id="text"><h1>爱的飞行日志</h1><p>赤道的边境</p><p>万里无云 天很清</p><p>爱你的事情</p><p>说了千遍 有回音</p><p>岸边的丘陵</p><p>崎岖不平 浪入侵</p><p>我却很专心</p><p>分辨得出 你的声音</p></div>
<script src="./js/axios.min.js"></script>
<!-- 封装了post请求的js -->
<script src="./js/post.js"></script>
<script>
// 第一个参数是文字所在dom,如id为text的div
// 第二个参数是所需的字体,如SourceHanSerifCN-Medium
fontmin('#text', "SourceHanSerifCN-Medium")
</script>
</body>
</html>
只要在页面里引用我们之前写的post.js,然后运行我们定义的fontmin()方法。
然后呢?试一下! 字体文件从13.8MB变成了19.0KB!
项目总结
- 后台:起一个nodejs,开发一个post接口,随调随用
- 前端: 页面上post请求
- 注意浏览器跨域问题
贴张项目完整文件目录图(这是本地测试时的项目目截图,js文件夹和index.html为前端页面及资源,express.js和fontmin.js为nodejs代码,fonts是源字体文件,font为切割字体后的文件目录)
关于配置代理
- 本地调试
方案1:通过nginx在本地做代理。
主要是把index.html(前端文件)放入nginx下的html目录中。
然后可以访问到127.0.0.1:端口/目录/index.html。
nodejs相关文件放哪里都行,只要运行起来就ok
配置代理,在conf文件,80端口上加上这段配置
location /getfontmin {proxy_pass http://127.0.0.1:3000/getfontmin;
}location /fontmin/ {root html;
}
好了,在浏览器打开http://127.0.0.1/fontmin/index.html
方案2:nginx在服务端做允许跨域配置。
这个不多说,网上文章一大堆
- 服务端配置
方案1:还是起nginx服务。
线上环境一样配置反向代理即可。
以接口请求的方式,解决移动端页面中字体文件过大的问题相关推荐
- css如何设置x轴为滚动,解决移动端页面出现 X轴横向滚动条问题
最近在用 Bootstrap 写一个需要适配 WEB 和 WAP 的网站,写完后发现 WAP 端总是会出现横向滚动条,也就是 X 轴滚动条,导致 WAP 端页面左右滑来滑去,很是令人蛋疼,即使设置了 ...
- php json转数组后并在前端展示,0516-如何从服务器端获取JSON格式字符串并解决到前端页面中显示...
一. 如何从服务器端获取JSON格式字符串并解决到前端页面中显示 1.采用AJAX异步方式从服务器请求必须为字符串的数据:例如 $PHP= '{"aaa":"bbb&q ...
- 解决Arcgis10.2.2中dbf文件用EXCEL打开乱码问题
解决Arcgis10.2.2中dbf文件用EXCEL打开乱码问题 参考文章: (1)解决Arcgis10.2.2中dbf文件用EXCEL打开乱码问题 (2)https://www.cnblogs.co ...
- C++57个入门知识点_50 菱形继承与虚继承(C++中语法允许多重继承造成菱形继承;会造成近亲结婚的问题;可以通过虚继承的方式解决;实际项目中不多用多重继承)
上篇C++57个入门知识点_49 多重继承与组合(一个类同时具有多个类的属性的方法:多重继承或者组合:多重继承:一个类同时继承多个类:多重继承构造和析构的顺序与普通继承类似:组合:类中包含多个成员对象 ...
- 解决移动端项目中苹果ios和安卓android手机点击输入框网页页面自动放大缩小
一.需求问题 在公司的项目开发中,我们经常需要开发移动端的项目.但是,在移动端中,点击输入框的时候,网页页面会自动放大或者缩小.这个也并不是我们所想要的,我们只需要向输入框中输入内容就可以了. 二.需 ...
- 如何禁止视频在手机移动端页面中全屏播放
最近公司的项目中出了需要在局部播放视频的需求,我们都知道HTML5中有一个专门的标签video用来嵌入视频.不过,这个video标签有很多的属性可能很多同学并不是很熟悉,下面我们来认识一下: 在网页里 ...
- 【loadrunner】解决将某个脚本中.c文件移植到其他脚本文件中,无法执行,且报Error -- Unresolved symbol错误问题
解决将某个脚本中XFZ_C2C_FBSP.c文件移植到其他脚本文件中,无法执行,报Error -- Unresolved symbol错误问题 步骤1:将XFZ_C2C_FBSP.c文件先copy至运 ...
- 【已解决】WPS/OFFICE中word文件可以打印,excel打印后无响应
问题 WPS/OFFICE中word文件可以打印,excel打印后无响应 博主用的是办公室同事共享的HP打印机,在使用过程中出现了WORD文件可以打印,但是EXCEL文件打印无反应,查看打印作业进程也 ...
- c语言中以追加只写方式打开文本文件,C语言中打开文件读取,写入的操作
#include#includeint main(){ //打开文件并以读取的方式 FILE* file = fopen("E://1.txt","rt"); ...
- 移动端页面中阻止视频全屏播放
最近公司的项目中出了需要在局部播放视频的需求,我们都知道HTML5中有一个专门的标签video用来嵌入视频.不过,这个video标签有很多的属性可能很多同学并不是很熟悉,下面我们来认识一下: 在网页里 ...
最新文章
- lucene,基于QueryParser的搜索
- zookeeper集群配置与配置文件详解
- 如何找到设备的guid_如何禁止win10自动更新显卡驱动
- Linux Shell脚本编程 --sort命令
- 【STM32】系统配置控制器相关函数和类型
- setTimeout(), nextTick(),setImmediate()区别 ZT~
- 一、设计模式 - UML (统一建模语言) - 类图
- vue axios封装及使用
- .Net FW上线报错:The OwinStartup attribute discovered in assembly ‘AppName‘.
- BP神经网络回归预测模型(python实现)
- 软件测试公司常见的部门有哪些?
- vosk实时语音识别
- php微信手机端上传图片,手机Wap微信端上传单图和上传多图的DEMO
- 用python抠图方便还是ps方便_我会Python之后都不屑用PS了,Python抠图太方便了!...
- python图片修改过、有原图、怎么得到改动的地方_Python-根据照片信息获取用户详细信息(微信发原图或泄露位置信息)...
- 数据库设计:需求分析
- 电脑网络被别的计算机控制,电脑被别人远程控制了,怎么办?
- 上海应届生落户政策计算机水平,2019年上海应届生落户的加分细则,上海的同学们必看!...
- OCR应用:证件识别
- PIM-SM原理(ASM)
热门文章
- C语言经典笔试题解析,原来微软笔试题也有简单的,C语言学习专题
- spoonwep破解方式使用心得
- python循环结构高一信息技术_高一信息技术For循环语句公开课【2019原创资源大赛】...
- 单片机c语言实验报告心得,关于单片机实训心得体会
- python热身教程_[转载]技术教程-MayaPython教程二之Python
- QT学习之基础Day1(自用)
- ffmpeg多种码率控制方式的实现
- java 字符替换_java string中的替换字符串
- 基于tensorflow的RNN中文自动写诗程序
- 游戏外挂篇:如何Dump内存获得游戏的辅助