
1、前言
我們都知道,微信小程式目前還不支持轉發朋友圈,可能現在Android是支持了,iOS還不支持,但總的來說還不能支持普遍機型,這樣假如我們需要推薦某個心儀的商品到朋友圈就沒法分享出去,于是就可以使用生成海報的形式,讓商品詳情頁的資訊顯示在一張圖片上,保存到手機相冊,然后發朋友圈,朋友可以長按識別海報上的小程式碼直達該商品詳情頁面,從而達到如同直接分享商品詳情頁的效果,

2、思路
之所以用戶掃碼能直接進入到我們指定的頁面,主要就是要靠海報上的那個太陽碼,也就是小程式碼,其他海報上的資訊或者漂亮的樣式純粹就是為了渲染海報圖片而已,
1、當用戶點擊按鈕生成海報時,我們要通過后臺介面生成并回傳小程式碼,要記得傳給后臺要塞入小程式碼的引數,比如這里要進入商品詳情頁就需要塞入商品id,如果還需要知道是誰分享的,那還要塞入用戶id,(這里有個問題留給大家思考,因為生成小程式碼的介面scene欄位長度最多是32位,如果我們需要傳的引數位數超過32該怎么辦,特別是資料庫主鍵是以uuid形式存盤的時候,那么傳2個引數的時候就會超過而無法呼叫介面)
2、保存海報按鈕,要檢測用戶是否已授權保存到手機相冊,如果已授權,則顯示保存海報按鈕,如果未授權則顯示授權并保存海報按鈕
3、用戶掃小程式碼,決議碼中scene引數,獲取到先前塞入的引數,比如商品id,用戶id,再呼叫商品詳情介面渲染資料即可,
3、效果

4、實作
分享圖片的components組件
index.wxml
<v-mask>
<view class="container">
<view class="canvas-wrapper">
<image class="icon" src="/images/icons/close.png" bindtap="onClose"></image>
<image class="shareImage" src="{{tempFilePath}}"></image>
</view>
<view class="button-wrapper">
<ly-button type="warning" i-class="custom-button" shape="circle" lang wx:if="{{saveImageAuth !== '1'}}" bindtap="saveImage" circle>保存海報</ly-button>
<ly-button type="warning" i-class="custom-button" shape="circle" lang wx:else bindtap="bindOpenSetting" circle>授權并保存海報</ly-button>
</view>
</view>
</v-mask>
<view class="hideCanvas">
<canvas canvas-id="shareCanvas" style="width: 750px;height: 1125px; zoom: {{unit}}"></canvas>
</view>
index.js
Component({
/**
* 組件的屬性串列
*/
properties: {
detail: Object
},
/**
* 組件的初始資料
*/
data: {
unit: 1, // 比例
saveImageAuth: '1', // 權限
tempFilePath: '', // 臨時圖片地址
},
lifetimes: {
attached() {
// 檢查授權權限
this.checkSaveImageAuth();
// //獲取用戶設備資訊,螢屏寬度
wx.getSystemInfo({
success: res => {
console.log('getSystemInfo', res)
this.setData({
unit: res.windowWidth / 750 * 0.8,
ratio: res.pixelRatio
})
}
})
this.drawCanvas()
}
},
/**
* 組件的方法串列
*/
methods: {
// 封裝的下載圖片函式
downLoadImage(url) {
return new Promise((resolve, reject) => {
wx.getImageInfo({
src: url,
success(res) {
resolve(res.path)
},
fail(err) {
reject(err)
},
complete() {
console.log('complete')
}
})
})
},
// 封裝的下載云存盤檔案函式
downLoadCloudFile(id) {
return new Promise((resolve, reject) => {
wx.cloud.downloadFile({
fileID: id,
success: res => {
// 回傳臨時檔案路徑
resolve(res.tempFilePath)
},
fail: err => {
console.log('err', err)
}
})
})
},
bindOpenSetting(e) {
let _this = this
wx.openSetting({
success(res) {
if (res.authSetting['scope.writePhotosAlbum']) {
_this.saveImage()
} else {
wx.showToast({
title: '請授權保存相冊權限,才能為您生成分享圖',
icon: 'none'
})
}
}
})
console.log('檢查權限', e)
},
// 檢查用戶授權權限
checkSaveImageAuth() {
let _this = this
wx.getSetting({
success(res) {
console.log('檢查用戶授權權限', res)
let auth = ''
// 有權限
if (res.authSetting['scope.writePhotosAlbum'] === true) {
console.log('2')
auth = '2'
// 無權限
} else if (res.authSetting['scope.writePhotosAlbum'] === false) {
console.log('1')
auth = '1'
} else {
// 未設定
console.log('0')
auth = '0'
}
_this.setData({
saveImageAuth: auth
})
}
})
},
drawCanvas() {
let detail = this.properties.detail;
let mallType = detail.mallType;
console.log('drawCanvas',detail);
let ctx = wx.createCanvasContext('shareCanvas', this)
let titleImage = this.downLoadImage('https://ysd-1300312604.cos.ap-shanghai.myqcloud.com/goods/goods_editor/20201022/c7bda103dcc24ce688743ec824b3dea0.png');
let productImage = this.downLoadImage(detail.productImage);
let erCodeImage = this.downLoadImage(detail.erCodeImage);
Promise.all([titleImage, productImage, erCodeImage]).then(imgs => {
console.log('imgs', imgs)
// 全部圖片下載成功
let bgWidth = 750;
let bgHeight = 1.5 * 750;
// 繪制白底背景
ctx.setFillStyle('#fff')
ctx.fillRect(0, 0, bgWidth, bgHeight)
console.log('全部圖片下載成功')
// 繪制頂部標題圖片
let titleOffLeft = (750 - 652) / 2;
let titleOffTop = 60;
let titleWidth = 652;
let titleHeight = 50;
// todo 偏移量需要再處理一下
ctx.drawImage(imgs[0], titleOffLeft, titleOffTop, titleWidth, titleHeight);
// 繪制產品圖片
let productOffLeft = 30;
let productOffTop = 155;
let productWidth = 690;
let productHeight = 380;
ctx.drawImage(imgs[1], productOffLeft, productOffTop, productWidth, productHeight)
// 繪制矩形邊框
ctx.lineWidth = 1;
ctx.strokeStyle = '#ccc';
ctx.rect(30, 156, 690, 670);
ctx.stroke();
// 繪制標題
ctx.setFillStyle('#333') // 文字顏色
ctx.font = `${32}px PingFang`; // 文字字號
let title1 = detail.title;
let title2 = '';
if (title1.length > 40) {
title2 = title1.substring(20, 39) + '...'
} else if (title1.length > 20) {
title2 = title1.substring(20)
}
title1 = title1.substring(0, 20)
let textWidth = ctx.measureText(title1).width;
let canvasWidthNoPadding = 750 - 56 * 2;
ctx.fillText(title1, 56, 595)
ctx.fillText(title2, 56, 630)
// 繪制副標題
ctx.setFillStyle('#ccc');
ctx.font = `28px PingFang`;
let subTitle = detail.subTitle;
if (subTitle.length > 23) {
subTitle = subTitle.substring(0, 22) + '...'
}
ctx.fillText(subTitle, 56, 695)
// 繪制價格
let priceIcon = '券后¥ ';
let price = String(detail.price); // 價格
let priceTail = '優惠券¥ ';
if (mallType == 3) {
priceIcon = '折后 ';
}
let couponAmount = String(detail.couponAmount);
ctx.font = '28px PingFang';
ctx.setFillStyle('#08B4DE');
ctx.fillText(priceIcon, 56, 770 );
let offsetPriceIcon = ctx.measureText(priceIcon).width;
ctx.font = '36px PingFang';
ctx.fillText(price, (56 + offsetPriceIcon), 770 );
if (detail.couponAmount != 0) {
let offsetPrice = ctx.measureText(price).width;
console.log('offsetPrice', offsetPrice)
if (mallType !=3) {
ctx.font = '28px PingFang';
ctx.fillText(priceTail, (360 + offsetPriceIcon + offsetPrice), 770 );
}
ctx.font = '36px PingFang';
let offsetPriceTailIcon = ctx.measureText(priceTail).width;
ctx.fillText(mallType !=3 ? couponAmount : couponAmount + ' 折', (330 + offsetPriceIcon + offsetPrice + offsetPriceTailIcon), 770 );
}
let linePriceIcon = (mallType != 4 ? mallType != 1 ? mallType != 2 ? mallType != 3 ? '拼多多': '唯品會' :'蘇寧': '京東': '淘寶') + '價 ';
let linePrice = String(detail.linePrice); // 價格
let saleNum = String(detail.saleNum) + '人已購';
ctx.font = '28px PingFang';
ctx.setFillStyle('#666');
ctx.fillText(linePriceIcon, 56, 818 );
let offsetLinePriceIcon = ctx.measureText(linePriceIcon).width;
ctx.font = '36px PingFang';
ctx.fillText(linePrice, (56 + offsetLinePriceIcon), 818 );
if (mallType != 3 && detail.saleNum != 0) {
let offsetLinePrice = ctx.measureText(linePrice).width;
ctx.font = '28px PingFang';
ctx.fillText(saleNum, (330 + offsetLinePriceIcon + offsetLinePrice), 818 );
}
// 繪制海報語資訊
let saleTitle = '先領券再購物,即領即用,讓你立省到家';
let saleName = detail.saleName;
let salePhone = String(detail.salePhone);
ctx.font = '24px PingFang';
ctx.setFillStyle('#08B4DE');
ctx.fillText(saleTitle, 30 , 930 );
ctx.setFillStyle('#666');
ctx.fillText(saleName, 30, 972 );
let saleNameWidth = ctx.measureText(saleName).width;
ctx.fillText(salePhone, 50 + saleNameWidth, 972 );
// 繪店鋪資訊
ctx.setFillStyle('#08B4DE');
let supplierName = `店鋪名稱:${detail.mallName}`;
let supplierNameWidth = ctx.measureText(supplierName).width;
ctx.fillText(supplierName, 50, 1036 );
this.roundRect(ctx, 30, 1006 , (supplierNameWidth + 40), 40, 20)
// 繪制二維碼
let ercodeDesc = '長按識別小程式碼領券';
ctx.setFillStyle('#bbb');
ctx.font = '22px PingFang';
let ercodeDescWidth = ctx.measureText(ercodeDesc).width;
let offsetErCode = (750 - 30) - ercodeDescWidth;
ctx.fillText(ercodeDesc, offsetErCode, 1078);
console.log('imgs', imgs[2])
ctx.drawImage(imgs[2], 540 , 860, 165, 165)
ctx.draw(true, () => {
let _this = this;
wx.canvasToTempFilePath({
x: 0,
y: 0,
canvasId: 'shareCanvas',
quality: 1.0,
fileType: 'jpg',
success(res) {
console.log('生成海報成功')
console.log('res', res)
_this.setData({
tempFilePath: res.tempFilePath
})
},
fail(err) {
console.log('err', err)
wx.showToast({
title: '海報生成失敗',
icon: 'none',
})
_this.triggerEvent('complete');
},
complete() {
}
}, _this)
})
}).catch(err => {
console.log(err)
})
},
onClose() {
wx.hideLoading();
this.triggerEvent('complete');
},
// 保存圖片
saveImage() {
let _this = this;
let tempFilePath = this.data.tempFilePath;
if (!tempFilePath) {
wx.showToast({
title: '海報生成失敗',
icon: 'none',
})
return;
}
wx.saveImageToPhotosAlbum({
filePath: tempFilePath,
success() {
wx.showToast({
title: '已保存到相冊,您可將海報分享到朋友圈',
icon: 'none'
})
_this.triggerEvent('complete');
},
fail() {
wx.showToast({
title: '海報保存失敗',
icon: 'none',
})
_this.checkSaveImageAuth()
},
complete() {
}
})
},
// 繪制圓角矩形
roundRect(ctx, x, y, w, h, r) {
if (w < 2 * r) {
r = w / 2;
}
if (h < 2 * r) {
r = h / 2;
}
ctx.beginPath();
ctx.setStrokeStyle('#ff7800');
ctx.setFillStyle('transparent')
ctx.setLineWidth(0.5);
ctx.moveTo(x + r, y);
ctx.arcTo(x + w, y, x + w, y + h, r);
ctx.arcTo(x + w, y + h, x, y + h, r);
ctx.arcTo(x, y + h, x, y, r);
ctx.arcTo(x, y, x + w, y, r);
ctx.stroke();
ctx.closePath();
},
},
})
在需要海報的頁面引入組件,比如要在detail模塊引入,則需要在detail.json檔案宣告組件
{
"usingComponents": {
"v-share-image": "/components/share-image/index"
}
}
然后在頁面detail.wxml參考即可
<v-share-image detail="{{tempInfo}}" wx:if="{{showShareImage}}" bind:close="onCloseShareImage" bind:complete="onConfirmShareImage"></v-share-image>

5、文末
限于篇幅并沒有貼出所有代碼,如果有需要的小伙伴可以,,,


【騰訊云】推廣者專屬福利,新客戶無門檻領取總價值高達2860元代金券,每種代金券限量500張,先到先得,
上一篇:一個欄位,就可以判斷是否關注公眾號,你信嗎
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/239540.html
標籤:其他
