运营后台上传一张图,同时页面生成小程序二维码,与运营上传的图合成一张大图,用于该页面在朋友圈的分享传播。html
背景图上传,调用接口实现文件上传到oss平台,生成背景图连接。vue
调用小程序二维码生成接口,生成该页面的二维码。详情参考小程序官方文档:developers.weixin.qq.com/miniprogram…。调用时注意参数长度有限制,若是参数过长会致使二维码生成失败。咱们采用的作法是跟小程序约定一套url映射规则,经过特定的参数来匹配对应的h5页面。web
将须要生成截图的html代码编写完整,其中包括背景图(运营上传的背景图),页面小程序二维码等其余元素。canvas
网上搜索了下,使用html2canvas插件能够实现截图功能,代码以下:小程序
// index.js import html2canvas from 'html2canvas'; html2canvas(this.$refs.shareImgElem, { useCORS: true, backgroundColor: null }) .then(canvas => { const dataUrl = canvas.toDataURL('images/jpg'); // 第一步:将dataUrl转换成Blob const blob = this.base64ToBlob(dataUrl); // 第二步:上传分享图 this.uploadShareImg(blob); }) 复制代码
// index.vue // 须要截图的html代码 <div ref="shareImgElem">....</div> // 截图图片的连接 <img :src="imgUrl" /> 复制代码
此时觉得将dataUrl保存下来,就能够完美解决这个需求了。然而事实大跌眼镜,截图生成的base64位的图是白屏的。网上也查询了html2canvas的用法,肯定调用方法没有写错,可是截出来的图就是空白的。后来查缘由,从最简单的demo开始写起,终于发现了白屏的缘由,现总结以下。api
截屏的代码里若是包含图片,图片须要设置容许跨域访问,不然js是读不到图片信息的。若是图片是放在cdn上,cdn须要设置cors相关设置,也就是图片请求的响应头里须要设置Access-Control-Allow-Origin: *跨域
咱们公司的图片是上传到阿里oss平台,oss里bucket设置跨域信息是控制图片上传时的域名来源的。而咱们是须要设置图片读取时能跨域,图片是存放在cdn上,因此联系运维在cdn配置里加上跨域信息便可。bash
图片请求的响应头里加上跨域信息后,截图看仍是白屏,接着继续找缘由,最后发现当截屏元素在首屏可见范围内就能够生成正确的截图。原来是在截图生成过程当中,若是鼠标在滚动,生成出来的截图在canvas画布上会有偏移。解决这个问题有两个操做:markdown
dom.setScrollTop(0); // 先滚动到最顶部 document.documentElement.style.position = 'fixed'; 复制代码
document.documentElement.style.position = ''; 复制代码
这时终于截图展现出来了。可是此时截图是base64编码的,这么大一串字符,存到后台不大合适,此时考虑将base64字符转换成blob二进制数据流,上传到oss。cors
转换代码以下:
// base64转换成blob数据 base64ToBlob(dataUrl, type) { var arr = dataUrl.split(','); var mime = arr[0].match(/:(.*?);/)[1] || type; // 去掉url的头,并转化为byte var bytes = window.atob(arr[1]); // 处理异常,将ascii码小于0的转换为大于0 var ab = new ArrayBuffer(bytes.length); // 生成视图(直接针对内存):8位无符号整数,长度1个字节 var ia = new Uint8Array(ab); for (var i = 0; i < bytes.length; i++) { ia[i] = bytes.charCodeAt(i); } return new Blob([ab], { type: mime }); } 复制代码
代码以下:
// 上传Blob二进制数据 uploadBlob(fileName, blob) { return new Promise((resolve, reject) => { async function putBlob() { try { let result = await ossClient.put(fileName, blob); result.imgUrl = `${CDN_IMAGE_DOMAIN}/${result.name}`; resolve(result); } catch (e) { reject(e); } } putBlob(); }); } 复制代码
// 上传分享大图 uploadShareImg(blob) { const fileName = `web/activityms/share_big_img_${Date.parse(new Date())}.jpg`; this .uploadBlob(fileName, blob) .then(res => { this.imgUrl = res.imgUrl; this.$message.success('朋友圈分享大图上传成功!'); }); } 复制代码
到此,截图生成成功,且成功上传到oss平台,并返回图片路径。