H5 -- (功能)基于html2canvas实现长按网页保存为图片到本地

1、需求:长按页面中的一部分(里面有动态获取的用户昵称、头像及动态生成的二维码),弹出下载框,点击后将这部分保存为图片下载到手机里(如图)

实例图片

2、分析:由于有动态获取数据,需等DOM元素生成之后,再将这一部分的DOM转化为canvas,再将canvas转为image,然后再实现长按image下载到本地 - - 一路走来,踩了不少坑,希望有此相似需求的能有所收获吧。
3、过程

第一步:数据渲染后,将 html 转化为 canvas

html2canvas.js可将一个元素渲染为canvas,只需要简单的调用html2canvas(element[, options])方法即可,html2canvas方法会返回一个包含有canvas元素的promise。

// 参数:element为要保存元素的DOM对象,option为可配置项
html2canvas(element, option).then(function(canvas) {

});

重点1:清晰度问题(最终图片的清晰度取决于html转换成的canvas的清晰度)
<1> 将原来的DOM元素的宽高设置为最终图片的2倍,然后canvas的宽高也要设置最终图片的2倍。(最好为设备的DPR倍)
<2> 设置原来的DOM元素的宽高时必须以px为单位,避免样式二次计算导致的模糊,切记~
例如:我的最终图片样式

// 生成的最终图片
#inviteImg {
   width: 5.6rem;   // rem适配:5.6rem * 50px/rem = 280px 
   height: 6.3rem;  // rem适配:6.3rem * 50px/rem = 315px 
}

则: 我的原来的DOM元素的样式

// 原来DOM盒子
#inviteBox {
   width: 560px;   // 最终图片宽度280px的2倍,以px为单位
   height: 630px;  // 最终图片高度315px的2倍,以px为单位
   position: absolute;
   z-index: -1;  // 离开屏幕
   background: transparent url("../assets/img/no.png");
   background-size: 560px 630px;
}

则:canvas的宽高

let self = this
let inviteBox = document.getElementById("inviteBox")
let canvas = document.createElement("canvas")
canvas.width = 560    // 最终图片宽度280px的2倍,以px为单位
canvas.height = 630   // 最终图片高度315px的2倍,以px为单位
let opts = {
   canvas: canvas,                       // 将自定义canvas作为配置项
   useCORS: true,                        // 允许图片跨域
   height: self.$refs.main.offsetHeight  // 修复截图不完整问题
}
html2canvas(inviteBox, opts).then((canvas) => {
/* 此处的base64ImgSrc就是得到的img的base64字符串,直接在页面上显示即可 */
let base64ImgSrc = canvas.toDataURL("image/png")

})

重点2:截图不全问题(当截图区域高度超出可视区域会截图不完整)
由于官网上提供的dom抓取不支持高度,都是从绝对定位的起点开始截取,会造成只可以截到浏览器可见的,如果截图区域高度超出可视区域会截图不完整

  • 可通过修改源码,可以支持完整截图(可以动态设置截图高度)

    未修改源码如下:(可通过查找进行修改~)

return renderDocument(node.ownerDocument, options, node.ownerDocument.defaultView.innerWidth, node.ownerDocument.defaultView.innerHeight, index).then(function(canvas) {        
    if (typeof(options.onrendered) === "function") {            
        log("options.onrendered is deprecated, html2canvas returns a Promise containing the canvas")           
        options.onrendered(canvas)    
        return canvas
    }
})

修改后源码如下:

/* 添加自定设置高度宽度 */   
var width = options.width != null ? options.width : node.ownerDocument.defaultView.innerWidth    
var height = options.height != null ? options.height : node.ownerDocument.defaultView.innerHeight    
return renderDocument(node.ownerDocument, options, width, height, index).then(function (canvas) {       
    if (typeof(options.onrendered) === "function") {            
        log("options.onrendered is deprecated, html2canvas returns a Promise containing the canvas")
        options.onrendered(canvas);        
    }        
})

修改源代码后重新引入修改后的html2canvas.js(需放到本地了),此时可将你要截取的高度通过配置项传入即可。

/* 将要截取的高度设置为最大盒子的高度并通过配置项传入 */
let self = this
let opts = {
   canvas: canvas,                    
   useCORS: true,                     
   height: self.$refs.main.offsetHeight  // 修复截图不完整问题
}

第二步:将canvas转化为png格式的image

上一步生成的canvas即为包含目标元素的元素对象。实现保存图片的目标只需要将canvas转image即可。

html2canvas(inviteBox, opts).then((canvas) => {
    let base64ImgSrc = canvas.toDataURL("image/png")
    /* 如果只是显示,可用以下代码 */
    let img = document.createElement("img")
    img.src = base64ImgSrc 
    document.body.appendChild(img)
})

重点:base64格式图片在前端可以显示,但是无法下载到本地,所以要将base64格式的图片转化为网络路径的png格式图片
我项目的解决方法为:将base64编码上传到七牛云然后获取到网络路径的png格式的图片,具体实现方法可参考:

如何上传base64编码图片到七牛云
上传base64图片到七牛云存储


第三步:长按image保存到本地

长按事件见:H5–(封装)移动端原生长按事件
下载保存图片:如果在pc端,且不考虑兼容性的话,可以使用htm15的a标签增加了download属性,可利用此属性实现图片下载,具体我就不细说,因为在手机端的webview中不好使。
我项目的解决方法为:与原生客户端交互,调取客户端的下载方法,传入图片的网络途径,客户端协助进行下载并存入相册。(ps:下载图片在webview中用h5真的实现不了,所以求助一下客户端小伙伴了~)


4、参考文档:

1、基于html2canvas实现网页保存为图片及图片清晰度优化 - - 小小云朵
2、html2canvas.js网页截图功能(解决截图不全问题) - - JugglerTao

猜你喜欢

转载自blog.csdn.net/weixin_41076513/article/details/80896399