分享圖.png
這里是
Geek小程序的源碼,點(diǎn)擊查看 github 源碼
前言
在開(kāi)發(fā)小程序的過(guò)程中,你是否有將頁(yè)面生成分享圖并引導(dǎo)用戶轉(zhuǎn)發(fā)至朋友圈的需求?有,那就進(jìn)來(lái)看看,應(yīng)該是你想要的結(jié)果。
在分享上,就目前來(lái)說(shuō),小程序是不能直接分享到朋友圈的,微信官方只開(kāi)放了分享到好友和群聊的 API。對(duì)于分享到朋友圈,現(xiàn)在大多數(shù)小程序所采用的方式,就是根據(jù)不同的需求生成一張帶小程序碼的圖片引導(dǎo)用戶分享至朋友圈。
當(dāng)然分享圖也可以在后臺(tái)生成,但是你懂得,基本沒(méi)有那個(gè)后臺(tái)大哥愿意為你去用代碼寫(xiě)一張圖出來(lái),所以,咱們還是自給自足,??。
歡迎大家使用微信掃描【組件庫(kù)小程序碼】(或者微信直接搜索組件庫(kù)演示)查看運(yùn)行效果
組件庫(kù)演示小程序.png
生成分享圖大致流程如下~

image.png
官方文檔
關(guān)于生成二維碼
- 微信官方獲取二維碼 API
- 如果每一次分享的二維碼不同,需要要生成
帶參數(shù)的二維碼 (采用接口B) - 生成的二維碼需要下載到本地
- 別忘了在
小程序微信公眾平臺(tái)后臺(tái)-設(shè)置-開(kāi)發(fā)設(shè)置-服務(wù)器域名-downloadFile 合法域名中添加域名
1. 使用 canvas 進(jìn)行繪制
我們知道小程序是支持將 canvas 直接轉(zhuǎn)換為圖片的,我們可以充分利用這個(gè)先決條件
1.1 拿到設(shè)計(jì)的效果圖,我們可以先按標(biāo)注計(jì)算出每個(gè)元素的寬高以及在畫(huà)布中的位置,建議使用 百分比,這樣可以對(duì)所有的屏幕大小進(jìn)行適配
示例代碼如下:
const temp = 0.01;
//圖片長(zhǎng)寬比
const scale = 1.78;
//背景圖高度
const bgScale = 0.5;
//頭像和寬的比
const avatarWidthScale = 0.368;
const avatarHeightScale = 0.117;
//頭像白色圓形背景
const avatarBgWidthScale = 0.38;
const avatarStrokeWidth = 4;
//昵稱高度比
const nicknameHeightScale = 0.34 + 5 * temp;
//第一行文字高度
const topTextScale = 0.515 + 3 * temp;
//分享內(nèi)容
const contentScale = 0.585 + 3 * temp;
const contentScale2 = 0.620 + 3 * temp;
//二維碼直徑
const qrCodeWidthScale = 0.341;
//二維碼高度
const qrCodeHeightScale = 0.69;
//極客文字
const bpbScale = 0.91 + temp * 2;
//識(shí)別文字
const decodeScale = 0.935 + temp * 2;
1.2 涉及到圖片繪制
- 本地圖片可以直接繪制
- 如果要繪制的元素中含有網(wǎng)絡(luò)圖片,需要先將圖片下載到本地,不然在真機(jī)上無(wú)法顯示(親測(cè)在模擬器上可以繪制,但在 iPhone6s 真機(jī)上無(wú)法顯示)
- 貼上頭像下載代碼:
/**
* 下載頭像
*/
downloadAvatar: function () {
var that = this;
wx.downloadFile({
url: that.data.avatar,
success: function (res) {
that.setData({
avatarPath: res.tempFilePath
})
that.drawImage();
},
fail: function () {
that.showErrorModel();
}
})
},
1.3 對(duì)各個(gè)元素進(jìn)行繪制
- 對(duì)于文字過(guò)長(zhǎng)省略...,目前沒(méi)有好的辦法,暫時(shí)采用的是設(shè)置最大文字長(zhǎng)度,超出截?cái)啵⑹謩?dòng)添加....
- 對(duì)于生成圓形頭像,可參考例子實(shí)現(xiàn)
drawImage: function () {
var that = this;
const ctx = wx.createCanvasContext('myCanvas', this);
var bgPath = '../../image/share-bg.png';
//設(shè)置 canvas 背景,不然生成的圖片背景會(huì)有黑色底
ctx.setFillStyle(WHITE);
ctx.fillRect(0, 0, windowWidth, windowHeight);
//繪制背景圖片
ctx.drawImage(bgPath, 0, 0, windowWidth, windowHeight * bgScale);
//頭像背景圓
ctx.arc(windowWidth / 2, avatarWidthScale / 2 * windowWidth + avatarHeightScale * windowHeight, (avatarWidthScale / 2) * windowWidth + avatarStrokeWidth, 0, 2 * Math.PI);
ctx.setFillStyle(WHITE);
ctx.fill();
//先繪制圓,裁剪成圓形圖片
ctx.save();
ctx.beginPath();
//圓的原點(diǎn)x坐標(biāo),y坐標(biāo),半徑,起始弧度,終止弧度
ctx.arc(windowWidth / 2, avatarWidthScale / 2 * windowWidth + avatarHeightScale * windowHeight, (avatarWidthScale / 2) * windowWidth, 0, 2 * Math.PI);
ctx.setStrokeStyle(WHITE);
ctx.stroke();
ctx.clip();
//繪制頭像
//圖片路徑,左上角x坐標(biāo),左上角y坐標(biāo),寬,高
var avatarWidth = avatarWidthScale * windowWidth;//頭像半徑
ctx.drawImage(that.data.avatarPath, windowWidth * (0.5 - avatarWidthScale / 2), avatarHeightScale * windowHeight, avatarWidth, avatarWidth);
ctx.restore();
//繪制 content
ctx.setFillStyle(GRAY_COLOR);
ctx.setFontSize(18);
ctx.setTextAlign('center');
ctx.fillText(that.data.detailStr.content, windowWidth / 2, contentScale * windowHeight);
ctx.setFillStyle(GRAY_COLOR);
ctx.setFontSize(18);
ctx.setTextAlign('center');
ctx.fillText(that.data.detailStr.contentOther, windowWidth / 2, contentScale2 * windowHeight);
//繪制二維碼
ctx.drawImage(that.data.QRPath, windowWidth * (0.5 - qrCodeWidthScale / 2), qrCodeHeightScale * windowHeight, qrCodeWidthScale * windowWidth, qrCodeWidthScale * windowWidth);
console.log('font------------>' + wx.canIUse('canvasContext.font'));
//繪制 按壓提示文字
ctx.setFillStyle(TINT_COLOR);
ctx.setFontSize(14);
ctx.setTextAlign('center');
ctx.fillText(that.data.detailStr.clickToMini, windowWidth / 2, decodeScale * windowHeight);
//繪制加粗文字--------------------------------------------------------------
//繪制昵稱
that.setFontStyle(ctx, 'bold');
ctx.setFillStyle(WHITE);
ctx.setFontSize(20);
ctx.setTextAlign('center');
ctx.fillText(stringUtil.substringStr(that.data.nickname), windowWidth / 2, nicknameHeightScale * windowHeight);
//繪制文字
ctx.setFillStyle(THEME_COLOR);
ctx.setFontSize(24);
ctx.setTextAlign('center');
ctx.fillText(that.data.detailStr.tip, windowWidth / 2, topTextScale * windowHeight);
//繪制 Geek小程序
ctx.setFillStyle(TINT_COLOR);
ctx.setFontSize(16);
ctx.setTextAlign('center');
ctx.fillText(that.data.detailStr.bpbMini, windowWidth / 2, bpbScale * windowHeight);
//繪制到 canvas 上
ctx.draw(false, function () {
console.log('callback--------------->');
that.saveCanvasImage();
});
}
1.4 兼容處理
- 一些 API 屬性是在高版本才有的,比如
文字加粗(基礎(chǔ)庫(kù) 1.9.90 開(kāi)始支持,低版本需做兼容處理) - 在使用之前用
wx.canIUse判斷
/**
* 改變字體樣式
*/
setFontStyle: function (ctx, fontWeight) {
if (wx.canIUse('canvasContext.font')) {
ctx.font = 'normal ' + fontWeight + ' ' + '14px' + ' sans-serif';
}
},
1.5 不同機(jī)型適配
- 可以拿主流的幾款手機(jī)適配,包括 ios 和 Android,沒(méi)有問(wèn)題的話,就可以進(jìn)行下一步了
2. 調(diào)整樣式
- 達(dá)到效果后修改
wxml以及wxss,對(duì) canvas 的樣式調(diào)整 - 確保 canvas 在屏幕可可顯示區(qū)域外,因?yàn)?canvas 的層級(jí)是最高的,我們直接在上面顯示圖片是不能顯示的,也不建議這么做(可以使用
cover-view) - 這個(gè)自由發(fā)揮,可以將 canvas 的
position設(shè)置為脫離文檔流(fixed),只要 canvas 不在屏幕顯示范圍即可,確保離可見(jiàn)區(qū)域足夠遠(yuǎn)
.canvas {
width: 100%;
position: fixed;
top: 9999rpx;
left: 0;
}
3. 將 canvas 保存為圖片
- 這是最后一步,給用戶展示分享圖片的同時(shí),用戶可以選擇保存圖片到手機(jī)相冊(cè)
3.1 注意處理用戶授權(quán)問(wèn)題
- 同時(shí)處理到用戶同意和拒絕權(quán)限
//轉(zhuǎn)化為圖片
saveCanvasImage: function () {
var that = this;
wx.canvasToTempFilePath({
canvasId: 'myCanvas',
success: function (res) {
console.log(res.tempFilePath);
that.setData({
targetSharePath: res.tempFilePath,
realShow: true
})
},
complete: function () {
that.hideLoading();
}
}, this)
},
/**
* 保存到相冊(cè)
*/
saveImageTap: function () {
var that = this;
that.requestAlbumScope();
},
/**
* 檢測(cè)相冊(cè)權(quán)限
*/
requestAlbumScope: function () {
var that = this;
// 獲取用戶信息
wx.getSetting({
success: res => {
if (res.authSetting['scope.writePhotosAlbum']) {
// 已經(jīng)授權(quán),可以直接調(diào)用 getUserInfo 獲取頭像昵稱,不會(huì)彈框
that.saveImageToPhotosAlbum();
} else {
wx.authorize({
scope: 'scope.writePhotosAlbum',
success(res) {
that.saveImageToPhotosAlbum();
},
fail() {
wx.showModal({
title: '提示',
content: '你需要授權(quán)才能保存圖片到相冊(cè)',
success: function (res) {
if (res.confirm) {
wx.openSetting({
success: function (res) {
if (res.authSetting['scope.writePhotosAlbum']) {
that.saveImageToPhotosAlbum();
} else {
console.log('用戶未同意獲取用戶信息權(quán)限-------->success');
}
},
fail: function () {
console.log('用戶未同意獲取用戶信息權(quán)限-------->fail');
}
})
}
}
})
}
})
}
}
})
},
3.2 保存圖片到相冊(cè)
saveImageToPhotosAlbum: function () {
var that = this;
wx.saveImageToPhotosAlbum({
filePath: that.data.targetSharePath,
success: function () {
wx.showModal({
title: '',
content: '??圖片保存成功,\n快去分享到朋友圈吧',
showCancel: false
})
that.hideDialog();
}
})
},
- 下面我將講解小程序自定義組件,以及對(duì)保存相冊(cè)的封裝,畢竟分享的地方會(huì)很多,封裝成組件會(huì)大大簡(jiǎn)化我們的代碼量以及工作量,這樣就可以少加點(diǎn)班,哈哈
- 簡(jiǎn)要流程就介紹到這里
- 更多細(xì)節(jié)參考 Geek 小程序源代碼
- 我是源代碼,點(diǎn)我,點(diǎn)我,快點(diǎn)我??

