由于我們無(wú)法將小程序直接分享到朋友圈,但分享到朋友圈的需求又很多猿妈,業(yè)界目前的做法是利用小程序的 Canvas 功能生成一張帶有小程序碼的圖片吹菱,然后引導(dǎo)用戶下載圖片到本地后再分享到朋友圈。相信大家在繪制分享圖中應(yīng)該踩到 Canvas 的各種彩蛋(坑)了吧~
這里首先推薦一個(gè)開(kāi)源的組件:painter(通過(guò)該組件目前我們已經(jīng)成功在支付寶小程序上也應(yīng)用上了分享圖功能)
咱們不多說(shuō)彭则,直接上手就是干鳍刷。
0.png
首先我們新增一個(gè)自定義組件,在該組件的json中引入painter
{
"component": true,
"usingComponents": {
"painter": "/painter/painter"
}
}
然后組件的WXML (代碼片段在最后)
<view class="share-wrap" wx:if="{{visible}}" catchtouchmove="preventDefault">
<view class="share-back"></view>
<view class="share-container">
<view class="close" bindtap="handleClose"></view>
<image mode="widthFix" src="{{sharePath}}" class="share-image" />
<view class="share-tips">保存圖片俯抖,叫伙伴們來(lái)參與吧</view>
<view class="save-btn" bindtap="handlePhotoSaved"></view>
</view>
</view>
<painter style="position: absolute; top: -9999rpx;" palette="{{imgDraw}}" bind:imgOK="onImgOK" />
接著組件的WXSS (代碼片段在最后)
.share-wrap {
width: 100%;
}
.share-back {
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.6);
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 888;
}
.share-container {
width: 100%;
background: #FFF;
position: fixed;
bottom: 0;
left: 0;
right: 0;
z-index: 999;
}
.close {
width: 30rpx;
height: 30rpx;
overflow: hidden;
position: absolute;
right: 64rpx;
top: 64rpx;
}
.close::after {
transform: rotate(-45deg);
}
.close::before {
transform: rotate(45deg);
}
.close::before,
.close::after {
content: '';
position: absolute;
height: 3rpx;
width: 100%;
top: 50%;
left: 0;
margin-top: -2rpx;
background: #9C9C9C;
}
.share-image {
width: 420rpx;
margin: 66rpx auto 0;
display: block;
border-radius: 16rpx;
box-shadow: 0px 4rpx 8px 0px rgba(0, 0, 0, 0.1);
}
.share-tips {
width: 100%;
text-align: center;
color: #3C3C3C;
font-size: 28rpx;
margin: 32rpx 0;
}
.save-btn {
width: 336rpx;
height: 96rpx;
margin: 0 auto 94rpx;
background: url('https://qiniu-image.qtshe.com/20190506save-btn.png') center center;
background-size: 100% 100%;
}
重點(diǎn)來(lái)了 JS (代碼片段在最后)
Component({
properties: {
//屬性值可以在組件使用時(shí)指定
isCanDraw: {
type: Boolean,
value: false,
observer(newVal, oldVal) {
newVal && this.drawPic()
}
}
},
data: {
imgDraw: {}, //繪制圖片的大對(duì)象
sharePath: '', //生成的分享圖
visible: false
},
methods: {
handlePhotoSaved() {
this.savePhoto(this.data.sharePath)
},
handleClose() {
this.setData({
visible: false
})
},
drawPic() {
if (this.data.sharePath) { //如果已經(jīng)繪制過(guò)了本地保存有圖片不需要重新繪制
this.setData({
visible: true
})
this.triggerEvent('initData')
return
}
wx.showLoading({
title: '生成中'
})
this.setData({
imgDraw: {
width: '750rpx',
height: '1334rpx',
background: 'https://qiniu-image.qtshe.com/20190506share-bg.png',
views: [
{
type: 'image',
url: 'https://qiniu-image.qtshe.com/1560248372315_467.jpg',
css: {
top: '32rpx',
left: '30rpx',
right: '32rpx',
width: '688rpx',
height: '420rpx',
borderRadius: '16rpx'
},
},
{
type: 'image',
url: wx.getStorageSync('avatarUrl') || 'https://qiniu-image.qtshe.com/default-avatar20170707.png',
css: {
top: '404rpx',
left: '328rpx',
width: '96rpx',
height: '96rpx',
borderWidth: '6rpx',
borderColor: '#FFF',
borderRadius: '96rpx'
}
},
{
type: 'text',
text: wx.getStorageSync('nickName') || '青團(tuán)子',
css: {
top: '532rpx',
fontSize: '28rpx',
left: '375rpx',
align: 'center',
color: '#3c3c3c'
}
},
{
type: 'text',
text: `邀請(qǐng)您參與助力活動(dòng)`,
css: {
top: '576rpx',
left: '375rpx',
align: 'center',
fontSize: '28rpx',
color: '#3c3c3c'
}
},
{
type: 'text',
text: `宇宙最萌藍(lán)牙耳機(jī)測(cè)評(píng)員`,
css: {
top: '644rpx',
left: '375rpx',
align: 'center',
fontWeight: 'bold',
fontSize: '44rpx',
color: '#3c3c3c'
}
},
{
type: 'image',
url: 'https://qiniu-image.qtshe.com/20190605index.jpg',
css: {
top: '834rpx',
left: '470rpx',
width: '200rpx',
height: '200rpx'
}
}
]
}
})
},
onImgErr(e) {
wx.hideLoading()
wx.showToast({
title: '生成分享圖失敗输瓜,請(qǐng)刷新頁(yè)面重試'
})
},
onImgOK(e) {
wx.hideLoading()
this.setData({
sharePath: e.detail.path,
visible: true,
})
//通知外部繪制完成,重置isCanDraw為false
this.triggerEvent('initData')
},
preventDefault() { },
// 保存圖片
savePhoto(path) {
wx.showLoading({
title: '正在保存...',
mask: true
})
wx.saveImageToPhotosAlbum({
filePath: path,
success: (res) => {
wx.showToast({
title: '保存成功',
icon: 'none'
})
setTimeout(() => {
this.setData({
visible: false
})
}, 300)
},
fail: (res) => {
wx.getSetting({
success: res => {
let authSetting = res.authSetting
if (!authSetting['scope.writePhotosAlbum']) {
wx.showModal({
title: '提示',
content: '您未開(kāi)啟保存圖片到相冊(cè)的權(quán)限,請(qǐng)點(diǎn)擊確定去開(kāi)啟權(quán)限尤揣!',
success(res) {
if (res.confirm) {
wx.openSetting()
}
}
})
}
}
})
setTimeout(() => {
wx.hideLoading()
this.setData({
visible: false
})
}, 300)
}
})
}
}
})
如此一個(gè)繪制分享圖的自定義組件就完成啦搔啊。
效果圖如下:
0.jpeg
tips:
- 暫不支持繪制圖片 圓角為:10rpx 0rpx 0rpx 0rpx 類似的。
- 文字居中實(shí)現(xiàn)可以看下我代碼片段
- 文字換行實(shí)現(xiàn)(maxLines)只需要設(shè)置寬度芹缔,maxLines如果設(shè)置為1坯癣,那么一行超出將會(huì)展示為省略號(hào)
當(dāng)然如果想支持四個(gè)圓角的 試試 把Pen.js文件78行的_doClip方法重寫(xiě),代碼:
_doClip(borderRadius, width, height) {
if (borderRadius && width && height) {
let border = borderRadius.split(' ')
let r1 = 0
let r2 = 0
let r3 = 0
let r4 = 0
if (border.length==1){
r1 = r2 = r3 = r4 = Math.min(border[0].toPx(), width / 2, height / 2);
}else{
r1 = Math.min(border[0] == 0 ? 0 : border[0].toPx(), width / 2, height / 2);
r2 = Math.min(border[1] == 0 ? 0 : border[1].toPx(), width / 2, height / 2);
r3 = Math.min(border[2] == 0 ? 0 : border[2].toPx(), width / 2, height / 2);
r4 = Math.min(border[3] == 0 ? 0 : border[3].toPx(), width / 2, height / 2);
}
//const r = Math.min(borderRadius.toPx(), width / 2, height / 2);
// 防止在某些機(jī)型上周邊有黑框現(xiàn)象最欠,此處如果直接設(shè)置 setFillStyle 為透明示罗,在 Android 機(jī)型上會(huì)導(dǎo)致被裁減的圖片也變?yōu)橥该鳎?iOS 和 IDE 上不會(huì)
// setGlobalAlpha 在 1.9.90 起支持,低版本下無(wú)效芝硬,但把 setFillStyle 設(shè)為了 white蚜点,相對(duì)默認(rèn)的 black 要好點(diǎn)
this.ctx.setGlobalAlpha(0);
this.ctx.setFillStyle('white');
this.ctx.beginPath();
this.ctx.arc(-width / 2 + r1, -height / 2 + r1, r1, 1 * Math.PI, 1.5 * Math.PI);
this.ctx.lineTo(width / 2 - r2, -height / 2);
this.ctx.arc(width / 2 - r2, -height / 2 + r2, r2, 1.5 * Math.PI, 2 * Math.PI);
this.ctx.lineTo(width / 2, height / 2 - r3);
this.ctx.arc(width / 2 - r3, height / 2 - r3, r3, 0, 0.5 * Math.PI);
this.ctx.lineTo(-width / 2 + r4, height / 2);
this.ctx.arc(-width / 2 + r4, height / 2 - r4, r4, 0.5 * Math.PI, 1 * Math.PI);
this.ctx.closePath();
this.ctx.fill();
// 在 ios 的 6.6.6 版本上 clip 有 bug,禁掉此類型上的 clip拌阴,也就意味著绍绘,在此版本微信的 ios 設(shè)備下無(wú)法使用 border 屬性
if (!(getApp().systemInfo &&
getApp().systemInfo.version <= '6.6.6' &&
getApp().systemInfo.platform === 'ios')) {
this.ctx.clip();
}
this.ctx.setGlobalAlpha(1);
}
}
主要是把borderRadius屬性Split為多個(gè)變量,然后一個(gè)一個(gè)判斷有沒(méi)有值迟赃。
使用方法(要么只給一個(gè)值陪拘,要么四個(gè)值都給):
borderRadius: '16rpx'
borderRadius: '16rpx 0 0 16rpx'