功能很簡單 但是有坑
廢話不多說直接上代碼
html
canvas 定義畫板 構(gòu)造海報(bào)? .preview 生成海報(bào)圖瀏覽 模板框?
<canvas canvas-id="shareImg" class="canvas-exp"></canvas>
<view hidden='{{previewHidden}}' class='preview'>
? <image src='{{preurl}}' mode='widthFix' class='previewImg'></image>
? <button type='primary' bindtap='save' style="background:#0A655A">保存到本地</button>
</view>
<button class='shares' type='primary' bindtap='share'>生成成績單</button>
css
.shares{
? position: absolute;
? bottom: 100rpx;
? width: 70%;
? left: 15%;
? height: 100rpx;
? line-height: 100rpx;
}
.canvas-exp{
? width:100%;height:606px;background:#fff;
}
.preview {
? width: 100%;
? height: 100%;
? background: rgba(0,0,0,1);
? position:fixed;
? top: 0;
? left: 0;
? z-index: 2;
}
.previewImg{
? width: 88%;
? position: absolute;
? top: 100rpx;
? left: 6%;
? z-index: 3;
? border: 1px solid #000;
? border-radius: 5px;
? max-height: 800rpx;
}
.preview button{
? width: 78%;
? position: absolute;
? top: 960rpx;
? left: 11%;
? border-radius: 2px;
}
.preview .cler{
? width: 64rpx;
? height: 64rpx;
? position: absolute;
? top: 1100rpx;
? left: 50%;
? margin-left: -32rpx;
}
核心代碼 js
// pages/all/index.js
Page({
? /**
? * 頁面的初始數(shù)據(jù)
? */
? data: {
? ? currentLineHeight: 0,
? ? previewHidden: true
? },
? onLoad(){
? ? this.createCanvasContext()
? },
? createCanvasContext() {
? ? let that =this
? ? var expiration = wx.getStorageSync("index_data_expiration"); //拿到過期時(shí)間
? ? var timestamp = Date.parse(new Date()); //拿到現(xiàn)在時(shí)間
? ? // access_token 過期時(shí)間
? ? if (wx.getStorageSync('access_token') && expiration > timestamp) {
? ? ? console.log(wx.getStorageSync('access_token'))
? ? ? that.accessToken(wx.getStorageSync('access_token'))
? ? } else {
? ? ? wx.request({
? ? ? ? url: 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=appid&secret=secret',
? ? ? ? method: 'get',
? ? ? ? success: function (ress) {
? ? ? ? ? wx.setStorageSync("access_token", ress.data.access_token)
? ? ? ? ? var timestamp = Date.parse(new Date());
? ? ? ? ? var expiration = timestamp + ress.data.expires_in
? ? ? ? ? console.log(ress.data.access_token)
? ? ? ? ? wx.setStorageSync("expires_in", expiration)
? ? ? ? ? that.accessToken(ress.data.access_token)
? ? ? ? },
? ? ? ? fail: function (res) {
? ? ? ? ? console.log(res)
? ? ? ? }
? ? ? })
? ? }
? },
? accessToken(access_token) {
? ? let that = this
? ? let winWidth = wx.getSystemInfoSync().windowWidth; // 獲取當(dāng)前設(shè)備的可視寬度
? ? let winHeight = wx.getSystemInfoSync().windowHeight; // 獲取當(dāng)前設(shè)備的可視高度
? ? that.setData({
? ? ? winWidth: winWidth,
? ? ? winHeight: winHeight
? ? })
? ? let data = {
? ? ? page: 'pages/hotinfo/hotinfo',
? ? ? scene: '12'
? ? }
? ? wx.request({
? ? ? url: 'https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=' + access_token,
? ? ? method: 'POST',
? ? ? data: data,
? ? ? // dataType: 'json',
? ? ? responseType: 'arraybuffer', //將返回?cái)?shù)據(jù) 按文本解析修改為arraybuffer
? ? ? success: function (res) {
? ? ? ? console.log(res)
? ? ? ? // 利用writeFile bese64圖片存本地文件使用
? ? ? ? var imgPath = wx.env.USER_DATA_PATH + '/tabhome' + 'ewm' + '.png';
? ? ? ? var fs = wx.getFileSystemManager();
? ? ? ? fs.writeFileSync(imgPath, res.data, "base64");
? ? ? ? ? const ctx = wx.createCanvasContext('shareImg')
? ? ? ? ? var Rpx = (winWidth / 375).toFixed(2);
? ? ? ? ? ctx.setFillStyle('#fff')
? ? ? ? ? ctx.fillRect(0, 0, winWidth, 800)
? ? ? ? ? ctx.drawImage('../../' + res[0].path, 0, 0, winWidth, 228 * Rpx)
? ? ? ? ? var currentLineHeight = 228 * Rpx + 10;
? ? ? ? ? ctx.setTextAlign('left')
? ? ? ? ? ctx.setFillStyle('#2E2F2F')
? ? ? ? ? ctx.setTextAlign('left')
? ? ? ? ? let contentTitle = '這世界,來過辐烂,愛過郑藏,奮斗過闸氮,何懼解決如何---悟空鹅心!這世界猎塞,來過垢乙,愛過渣慕,奮斗過,何懼解決如何---悟空裂逐!'
? ? ? ? ? var chr = contentTitle.split(""); //這個(gè)方法是將一個(gè)字符串分割成字符串?dāng)?shù)組
? ? ? ? ? var temp = "";
? ? ? ? ? var row = [];
? ? ? ? ? for (var a = 0; a < chr.length; a++) {
? ? ? ? ? ? if (ctx.measureText(temp).width < winWidth / 2 - 10) {
? ? ? ? ? ? ? temp += chr[a];
? ? ? ? ? ? } else {
? ? ? ? ? ? ? a--;
? ? ? ? ? ? ? row.push(temp);
? ? ? ? ? ? ? temp = "";
? ? ? ? ? ? }
? ? ? ? ? }
? ? ? ? ? row.push(temp);
? ? ? ? ? //如果數(shù)組長度大于2 則截取前兩個(gè)
? ? ? ? ? if (row.length > 2) {
? ? ? ? ? ? var rowCut = row.slice(0, 2);
? ? ? ? ? ? var rowPart = rowCut[1];
? ? ? ? ? ? var test = "";
? ? ? ? ? ? var empty = [];
? ? ? ? ? ? for (var a = 0; a < rowPart.length; a++) {
? ? ? ? ? ? ? if (ctx.measureText(test).width < winWidth / 2 - 10) {
? ? ? ? ? ? ? ? test += rowPart[a];
? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? empty.push(test);
? ? ? ? ? ? var group = empty[0] + "..." //這里只顯示兩行歹鱼,超出的用...表示
? ? ? ? ? ? rowCut.splice(1, 1, group);
? ? ? ? ? ? row = rowCut;
? ? ? ? ? }
? ? ? ? ? ctx.font = 'normal bold 18px sans-serif';
? ? ? ? ? for (var b = 0; b < row.length; b++) {
? ? ? ? ? ? currentLineHeight += Rpx * 30;
? ? ? ? ? ? ctx.fillText(row[b], 15, currentLineHeight);
? ? ? ? ? }
? ? ? ? ? currentLineHeight += 80 * Rpx
? ? ? ? ? ctx.drawImage('../../' + 'assets/coupon_gold.png', 20, currentLineHeight, 60 * Rpx, 60 * Rpx)
? ? ? ? ? currentLineHeight += 35 * Rpx
? ? ? ? ? ctx.fillText('健健康康', 90 * Rpx, currentLineHeight);
? ? ? ? ? ctx.drawImage(imgPath, winWidth - 120 * Rpx, currentLineHeight - 70, 100 * Rpx, 100 * Rpx)
? ? ? ? ? currentLineHeight += 100 - 40 * Rpx
? ? ? ? ? ctx.stroke()
? ? ? ? ? ctx.draw()
? ? ? ? ? that.setData({
? ? ? ? ? ? currentLineHeight: currentLineHeight
? ? ? ? ? })
? ? ? ? })
? ? ? }
? },
? save: function () {
? ? var that = this;
? ? //獲取相冊(cè)授權(quán)
? ? wx.getSetting({
? ? ? success(res) {
? ? ? ? if (!res.authSetting['scope.writePhotosAlbum']) {
? ? ? ? ? wx.authorize({
? ? ? ? ? ? scope: 'scope.writePhotosAlbum',
? ? ? ? ? ? success() {
? ? ? ? ? ? ? that.savaImageToPhoto();
? ? ? ? ? ? }
? ? ? ? ? })
? ? ? ? } else {
? ? ? ? ? that.savaImageToPhoto();
? ? ? ? }
? ? ? }
? ? })
? },
? /**
? * 生成分享圖
? */
? share: function () {
? ? var that = this
? ? wx.showLoading({
? ? ? title: '努力生成中...'
? ? })
? ? wx.canvasToTempFilePath({
? ? ? x: 0,
? ? ? y: 0,
? ? ? width: this.data.winWidth,
? ? ? height: this.data.currentLineHeight,
? ? ? destWidth: this.data.winWidth,
? ? ? destHeight: this.data.currentLineHeight,
? ? ? canvasId: 'shareImg',
? ? ? success: function (res) {
? ? ? ? console.log(res.tempFilePath);
? ? ? ? that.setData({
? ? ? ? ? preurl: res.tempFilePath,
? ? ? ? ? previewHidden: false,
? ? ? ? })
? ? ? ? wx.hideLoading()
? ? ? },
? ? ? fail: function (res) {
? ? ? ? console.log(res)
? ? ? }
? ? })
? },
? savaImageToPhoto: function () {
? ? let that = this;
? ? wx.showLoading({
? ? ? title: '努力生成中...'
? ? })
? ? wx.canvasToTempFilePath({
? ? ? x: 0,
? ? ? y: 0,
? ? ? width: that.data.winWidth,
? ? ? height: that.data.winHeight - 70,
? ? ? destWidth: that.data.winWidth,
? ? ? destHeight: that.data.winHeight - 70,
? ? ? canvasId: 'shareImg',
? ? ? success: function (res) {
? ? ? ? console.log(res)
? ? ? ? wx.hideLoading()
? ? ? ? wx.saveImageToPhotosAlbum({
? ? ? ? ? filePath: res.tempFilePath,
? ? ? ? ? success(res) {
? ? ? ? ? ? wx.showModal({
? ? ? ? ? ? ? content: '圖片已保存到相冊(cè)',
? ? ? ? ? ? ? showCancel: false,
? ? ? ? ? ? ? confirmText: '知道啦',
? ? ? ? ? ? ? confirmColor: '#72B9C3',
? ? ? ? ? ? ? success: function (res) {
? ? ? ? ? ? ? ? if (res.confirm) {
? ? ? ? ? ? ? ? ? console.log('用戶點(diǎn)擊確定');
? ? ? ? ? ? ? ? ? that.setData({
? ? ? ? ? ? ? ? ? ? hidden: true
? ? ? ? ? ? ? ? ? })
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? }
? ? ? ? ? ? })
? ? ? ? ? }
? ? ? ? })
? ? ? },
? ? ? fail: function (res) {
? ? ? ? console.log(res)
? ? ? }
? ? })
? },
})
https://api.weixin.qq.com只能用后端請(qǐng)求獲取 前端只可供體驗(yàn)參考 不然線上會(huì)出問題
1.通過小程序api 接口?https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=appid&secret=secret? (get)
獲取 token值? 時(shí)效兩個(gè)小時(shí)?
2.再通過api 接口?https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=access_token 獲取自定義參數(shù)的小程序碼?(POST)
01.scene 為要攜帶的參數(shù) 最高32位? ?具體看小程序api文檔? 接口返回的格式為?arraybuffer
02.請(qǐng)求是注意? 參數(shù)修改??responseType: 'arraybuffer', //將返回?cái)?shù)據(jù) 按文本解析修改為arraybuffer
03.通過api?wx.arrayBufferToBase64() 將數(shù)據(jù)轉(zhuǎn)為bese64? ?例:
let URL ='data:image/png;base64,' + wx.arrayBufferToBase64(res.data)
04.小程序canvas bese64圖片 模擬器可正常顯示?真機(jī)操作則無效? 因canvas圖片不支持base64?
處理方法為利用writeFile bese64圖片存本地文件使用 例:
var imgPath = wx.env.USER_DATA_PATH + '/tabhome' + 'ewm' + '.png';
var fs = wx.getFileSystemManager();
fs.writeFileSync(imgPath, res.data, "base64");
wx.env.USER_DATA_PATH 為微信提供無需在意? ?'/tabhome' 為本頁面路徑?ewm為自定義
writeFileSync內(nèi)的imgPath為自定義的文件路徑 (本地路徑)?
writeFileSync內(nèi)的res.data 為獲取到的arraybuffer值?
writeFileSync內(nèi)的base64 為數(shù)據(jù)類型
imgPath拿到的 就是本地的圖片路徑 可直接使用到項(xiàng)目中
3.利用wx.createCanvasContext創(chuàng)建畫板 進(jìn)行繪畫?文字太多 自動(dòng)換行兩行省略處理 圖片路徑一定要正確 不然只會(huì)看到空白的canvas
4.利用wx.canvasToTempFilePath() 將canvas截取生成圖片? 區(qū)域可自定義 具體請(qǐng)看官方文檔
5.wx.saveImageToPhotosAlbum? 保存圖片到手機(jī)相冊(cè)
流程:
通過canvas提前繪制海報(bào)
再通過wx.canvasToTempFilePath() 截取繪制好的海報(bào)
最后通過wx.saveImageToPhotosAlbum? 保存圖片到手機(jī)相冊(cè)
這樣就大功告成了