運營後臺上傳一張圖,同時頁面生成小程序二維碼,與運營上傳的圖合成一張大圖,用於該頁面在朋友圈的分享傳播。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畫布上會有偏移。解決這個問題有兩個操做:cors
dom.setScrollTop(0); // 先滾動到最頂部
document.documentElement.style.position = 'fixed';
複製代碼
document.documentElement.style.position = '';
複製代碼
這時終於截圖展現出來了。可是此時截圖是base64編碼的,這麼大一串字符,存到後臺不大合適,此時考慮將base64字符轉換成blob二進制數據流,上傳到oss。運維
轉換代碼以下:
// 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平臺,並返回圖片路徑。