利用JS生成二维码图片,优化WEB性能及页面加载速度 | 张戈博客
一、意淫场景
2年前接触网站建设后,二维码也进入了我折腾的范围,当时意淫了这样一个场景:当用户首次在别人电脑上看到我们的网站时,突然有事要离开,但是这个网页内容很赞,实在难以割舍,他该怎么办?
我继续意淫了多个解决办法:
①、复制这个网页,通过QQ发送到我的设备(那时候貌似还没有这个功能。。。)
②、收藏到类似QQ云收藏等在线收藏夹,或保存为文本存在云盘,以后再看
③、死记硬背也要记住这个网页地址,然后回家继续看
④、赶紧掏出手机,在手机浏览器里面输入网页地址继续看
。。。。
N、尼玛这网页为毛就不能提供一个二维码,让我用QQ浏览器扫一扫继续看呢?
很明显,在这种场景下,网页上如果能提供一个二维码就能给网站增加一个忠实访客,甚至是粉丝。
二、后台实现
我这人把,技术不行,但只要有想法就立马付诸实践,认为技术再难也不会是瓶颈。
博客用的语言是php,因为第一时间用php实现了这个功能,应用到网站就是这个样子:
源码也非常简单,感兴趣的看下:https://zhang.ge/5031.html
三、前台实现
本来这个PHP二维码用得挺好的,反正做了CDN缓存,速度负载都不用考虑。最近在一个国外的网站看一个源码的时候,好奇的看看网页的二维码是什么地址是,发现居然是canvas生成的!
是咯,为毛之前我没想到JS生成二维码这一茬呢?
果然还是想法和见识更重要啊!知道有这个途径,怎么实现基本是小菜一碟了。
顺手百度了一下,果然一堆教程,而且个个历史悠久,看来自己out怪不得别人。
实现很简单,DEMO如下:
<html>
|
|
<head>
|
|
<meta charset='utf-8'>
|
|
<script src='//libs.cdnjs.net/jquery/1.8.2/jquery.min.js'></script>
|
|
<script src='//libs.cdnjs.net/jquery.qrcode/1.0/jquery.qrcode.min.js'></script>
|
|
</head>
|
|
<body>
|
|
<div id='output'></div>
|
|
<script type='text/javascript'>
|
|
content = 'https://zhang.ge/';
|
|
$('#output').qrcode({
|
|
width: 200,
|
|
height: 200,
|
|
render: 'canvas',
|
|
correctLevel: 0,
|
|
text: content
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|
丢到SAE试了下,效果还不错:http://atools.sinaapp.com/demo.html
更多参数如下:
render : 'canvas',//设置渲染方式 width : 256, //设置宽度 height : 256, //设置高度 typeNumber : -1, //计算模式 correctLevel : QRErrorCorrectLevel.H,//纠错等级 background : '#ffffff',//背景颜色 foreground : '#000000' //前景颜色
四、中文兼容
从分享这个教程的博客那知道,上述JS生成二维码是不支持中文内容的,而少数个人博客可能会使用中文的url路径,那么就不适用了。
其实,要解决也挺简单,只要二维码编码前把字符串转换成UTF-8即可。
博主也提供相关JS转换代码:
function utf16to8(str) {
|
|
var out, i, len, c;
|
|
out = '';
|
|
len = str.length;
|
|
for(i = 0; i < len; i++) {
|
|
c = str.charCodeAt(i);
|
|
if ((c >= 0x0001) && (c <= 0x007F)) {
|
|
out += str.charAt(i);
|
|
} else if (c > 0x07FF) {
|
|
out += String.fromCharCode(0xE0 | ((c >> 12) & 0x0F));
|
|
out += String.fromCharCode(0x80 | ((c >> 6) & 0x3F));
|
|
out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
|
|
} else {
|
|
out += String.fromCharCode(0xC0 | ((c >> 6) & 0x1F));
|
|
out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
|
|
}
|
|
}
|
|
return out;
|
|
}
|
因此,如果内容含有中文,就需要用这个函数先转码,比如前文的DEMO修改如下:
<html><head><meta charset='utf-8'><script src='//libs.cdnjs.net/jquery/1.8.2/jquery.min.js'></script><script src='//libs.cdnjs.net/jquery.qrcode/1.0/jquery.qrcode.min.js'></script></head><body><div id='output'></div><script type='text/javascript'>function utf16to8(str) {var out, i, len, c;out = '';len = str.length;for (i = 0; i < len; i++) {c = str.charCodeAt(i);if ((c >= 0x0001) && (c <= 0x007F)) {out += str.charAt(i);} else if (c > 0x07FF) {out += String.fromCharCode(0xE0 | ((c >> 12) & 0x0F));out += String.fromCharCode(0x80 | ((c >> 6) & 0x3F));out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));} else {out += String.fromCharCode(0xC0 | ((c >> 6) & 0x1F));out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));}}return out;}content = utf16to8('手机扫一扫,精彩随声带!');$('#output').qrcode({width: 200,height: 200,render: 'canvas',correctLevel: 0,text: content});</script></body></html>
参考文章:http://suflow.iteye.com/blog/1687396
五、Begin主题
Ps:哈,突然发现鸟哥博客已经用上了,看来我们想到一起去了,相信begin新版本就会集成。
说了半天代码和demo,可能还是有很多朋友不会用,下面再简单介绍下把js生成二维码集成到Begin的方法。
Begin还是在上几个版本就已经集成了二维码图片功能,不过用的是外部api生成的,加载速度差强人意。当然,到了张戈博客,第一时间就换成了自建的php二维码api了。
现在get到了新技能,所以我也第一时间也将博客的二维码改成了js方式了,修改很简单:
①、加载js代码:
<script src='//libs.cdnjs.net/jquery.qrcode/1.0/jquery.qrcode.min.js'></script>
|
将上述代码添加到Begin主题的header.php或footer.php当中(也可以将上述js文件的内容合并到主题的全局js,比如scripts.js)。
②、修改php代码:
编辑 begin/inc/scroll.php 这个文件,如下修改即可:
<ul id='scroll'>
|
|
<?php if (zm_get_option('qr_img')) { ?><li><a class='qr' title='二维码'><i class='fa fa-qrcode'></i></a></li><?php } ?>
|
|
<li><a class='scroll-t' title='返回顶部'><i class='fa fa-angle-up'></i></a></li>
|
|
<?php if(is_single() || is_page()) { ?><li><a class='scroll-c' title='评论'><i class='fa fa-comment-o'></i></a></li><?php } ?>
|
|
<li><a class='scroll-b' title='转到底部'><i class='fa fa-angle-down'></i></a></li>
|
|
</ul>
|
|
<?php if (zm_get_option('qr_img')) { ?>
|
|
<!-- table模式下修复点阵过于分散导致二维码扫描失效问题 -->
|
|
<style>.qr-img td { border: none;padding: 0;}</style>
|
|
<span class='qr-img'>
|
|
<img class='alignnone' src='https://res.zgboke.com/favicon.ico' style='position: absolute;top: 75px;right: 75px;width: 30px;height: 30px;'>
|
|
<div id='qr-img'></div>
|
|
<div id='floatbtn-qr-msg'>手机扫一扫 精彩随身带</div>
|
|
</span>
|
|
<script type='text/javascript'>
|
|
if(!+[1,]){ /* 新增判断:如果是IE浏览器,则使用table兼容方式 */
|
|
Render = 'table';
|
|
} else {
|
|
Render = 'canvas';
|
|
}
|
|
$('#qr-img').qrcode({width:150,height:150,render:Render,correctLevel:0,text:window.location.href});
|
|
</script>
|
|
<?php } ?>
|
每个<li>代表一个按钮,上下位置自行按需调整即可。全部完成之后,彻底刷新各种缓存,就能看到前文贴图一样的效果了!其他主题只需参考折腾即可。
Tips:
上述代码也未加入中文兼容,如有需求,只需要继续增加兼容中文的 js 代码,然后把
content = window.location.href;
改成
content = utf16to8(window.location.href);
即可搞定。
六、兼容方案
前几天,鸟哥反馈我博客在IE8会导致整个浏览器卡死的问题!我苦逼定位了2个多小时才搞定!
定位方法非常苦逼:
①、先移除所有JS,测试依然卡B
②、移除wp_footer()输出,测试依然卡B
③、移除wp_header()输出,好了!!
尼玛,发现问题出现在头部输出里面,于是分别开启和关闭头部输出,得出头部输出内容,然后一项一项添加上去看是否会卡B。
最终,发现居然是一个我自定义的CSS代码导致的???原来是一个CSS属性的大括号被我写成了中文符号},真是R了狗了。。。
在测试中,我发现IE下无法生成二维码,于是脑补了下,发现IE不支持canvas模式,只支持table模式。
因此多写一个判断搞定:
<script type='text/javascript'>
|
|
if(!+[1,]){ /* 新增判断:如果是IE浏览器,则使用table兼容方式 */
|
|
Render = 'table';
|
|
} else {
|
|
Render = 'canvas';
|
|
}
|
|
$('#qr-img').qrcode({width:150,height:150,render:Render,correctLevel:0,text:window.location.href});
|
|
</script>
|
Ps:没错,这也是史上最短的IE判断,大家可以记录下,以备后用。
等使用table模式后,发现生成的二维码惨不忍睹,而且还扫不了:
后来和鸟哥交流的时候,他说是这主题table样式有冲突,重新下指定下二维码的table属性即可:
<!-- table模式下修复点阵过于分散导致二维码扫描失效问题 --><style>.qr-img td { border: none;padding: 0;}</style>
其实,table模式就是黑白表格组合原理,主题定义的表格样式把qrcode生成的二维码搞成了鬼样。
Ps:此项修复已加入到上一步Begin代码中,其他主题请自行参考。
七、对比分析
本文介绍的二维码是每个页面动态生成的二维码,扫码后打开的也是当前页面,但是不管是静态还是动态,图片加载的方式总是要产生一个http 请求的,当页面处于海量访问时就会带来一定的负载了。。。
但是,如果使用js生成二维码的方式,这图片就在前台浏览器生成的了。抛开JS的兼容性不说,在海量请求场景应该可以极大的减少http请求量吧?
当然,JS生成方式需要多载入一个Jquery.qrcode.min(通用JQ一般都有,就不算了)。看了下,这个JS只有13KB:
而且,我们完全可以把他合并到其他JS当中,那就连http请求都省了!可见,换成JS方式的性价比还是比较可观的!当然,JS的兼容性就另说了,这里就不多说了,感兴趣的可以试试。