网易哒哒的 H5 一向是业界精品,其中不少 H5 会成为爆款,能在朋友圈广泛流传的那种。同时,他们还写了一本很水的书——制造爆款:H5营销策划一本通,草草介绍了下各式各样的H5,但相关的技术文章却都没这么介绍,笔者一直想仿做类似的H5,找来找去,也只找到两篇网易同厂的技术类文章:

就此,笔者做个简易H5,介绍一下个人认为H5中比较重要的功能点——长按保存图片及识别二维码

此项目主要用到三个库

前期准备

设计稿:魔改公司H5中的其中一页

字体:寻找开源字体,这款不错——LXGW WenKai / 霞鹜文楷

此外,就是布局,笔者在移动端法门:自适应方案和高清方案 中阐述过一个观点:

不同的布局方式作用不同,像新闻类的H5,采用 px 为单位,是为了让大手机看到更多的信息;像应用型的H5,采用 rem/vw 为单位,力求在各种手机上能保持一致UI

像营销页面,是希望在各种手机上保持UI一致,理论上采用 rem/vw 是没问题的,但是 ggvswild 在高质量前端快照方案:来自页面的「自拍」 中曾说:

为了给到html2canvas明确的整数计算值,避免因小数舍入而导致的拉伸模糊,建议将布局中使用中使用%vwvhrem等单位的元素样式,统一改为使用px

而笔者在实际项目开发时,采用 rem 为单位并没有发现拉伸模糊问题。除此之外,笔者又寻找了几个网易的 H5

个人总结:在布局上它们都使用绝对定位布局,在长度单位上各有特色,所以做 H5 布局是无所谓用那种方式,只要在截图页不让元素拉伸即可,也就是说如果拉伸模糊了,可查一下此元素的单位是否是小数,至于其他页的布局,习惯用那个就用那个

实战开始

字体的运用

字体「 霞鹜文楷」大约4.4M,太大了,用 fontmin 提取用到的字体,这里我直接使用 Fontmin 的客户端,无它,命令行执行出错,营销页只用到了9个汉字,裁剪后从4.4M减少到 44kb

二维码功能的实现

很简单,看文档就能学会

1
2
3
4
5
6
7
8
var qrcode = document.getElementById("qrcode")
new QRCode(qrcode, {
width: 200,
height: 200,
colorDark: "#000000",
colorLight: "#ffffff",
correctLevel: QRCode.CorrectLevel.L
}).makeCode(window.location.href)

快照实现

将 html2canvas 和 canvas2image 结合,将 HTML 转成 base64 图片,而这一功能可以做成一个库:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
var convertToImage = (function () {

function createBaseCanvas(scale, width, height) {
const canvas = document.createElement('canvas');

canvas.width = width * scale;
canvas.height = height * scale;

const context = canvas.getContext("2d");

// 关闭抗锯齿
context.mozImageSmoothingEnabled = false;
context.webkitImageSmoothingEnabled = false;
context.msImageSmoothingEnabled = false;
context.imageSmoothingEnabled = false;

context.scale(scale, scale);

return canvas;
}

function convertToImage(container, options = {}) {
const scale = window.devicePixelRatio;

const width = container.offsetWidth;
const height = container.offsetHeight;

const canvas = createBaseCanvas(scale, width, height);

const ops = {
useCORS: true, // 如果截图的内容里有图片,解决文件跨域问题
allowTaint: false, // 是否允许跨源图像污染画布
...options
};

return html2canvas(container, ops).then(canvas => {
const imageEl = Canvas2Image.convertToPNG(canvas, canvas.width, canvas.height)
return imageEl
})
}
return convertToImage
})()

使用:

1
2
3
convertToImage(document.querySelector("#capture")).then((imageEl) => {
document.getElementsByClassName("save")[0].appendChild(imageEl)
})

canvas2image 的坑点

  1. 最新版本(1.4.1)已支持缩放,已解决图片不清晰的问题
    • 图片不清晰以前是个大问题,不少博文都有对其说明,目前的版本没看到模糊
  2. 文档上写支持 background-image:linear-gradient(),但是如果是渐变至透明是不行的

渐变背景色

而我希望呈现这样的样式:

背景图

背景渐变方案:

1
background-image: linear-gradient(90deg, $white, transparent);

改成背景图:

1
2
background: url('../bg.png') no-repeat;
background-size: 100% 100%;
  1. 文字会出现位移,这个问题至今一直存在,作者也没有修复

以上就是所遇到的问题,像跨域之类的问题,随着时间的推移,文档上都有说明,已经不是什么问题

线上预览地址:这里

2023.3.14 更新

文字会出现位移小爝 给出了方案html2canvas 文字向下偏移兼容方法,主要改动源码中的两点:

1
2
// var baseline = img.offsetTop - span.offsetTop +2;
var baseline = parseInt(getComputedStyle(span,null).lineHeight,10) - 5;
1
_this.ctx.textBaseline = 'alphabetic';

主要是修正字体的基准位移。给我开了一个思路,找不到解决方案就直接去找源码debugger

参考资料