業(yè)務(wù)場景
二輪充電業(yè)務(wù)中,用戶充電完成后在訂單詳情頁展示訂單相關(guān)信息,用戶點擊分享按鈕喚起微信小程序分享菜單,將生成的圖片海報分享給微信好友或者下載到本地,好友可通過掃描海報中的二維碼加群領(lǐng)取優(yōu)惠。
使用場景及功能:微信小程序 生成海報圖片 分享好友 下載圖片
使用技術(shù):Taro vue vant Canvas
實現(xiàn)效果圖
重點步驟拆分
1、封裝一個海報分享組件 poster-share.vue
2、用canvas畫圖,將背景圖、費用、二維碼等信息繪制在一張圖上,其中費用、二維碼是動態(tài)獲取的
3、生成一張本地緩存圖片
4、喚起微信分享功能,實現(xiàn)分享和下載功能
重點步驟有了,那么就開干吧!
核心代碼實現(xiàn)
1、模版部分
需要一個畫布dom用來繪制圖片,一個用來存放生成圖片的dom
問:canvasId為什么需要動態(tài)生成呢?
答:避免一個頁面中使用多個組件引起的canvasId重復(fù)問題
<template> <div class="poster-share__content"> <!-- canvas生成的海報圖片 --> <img v-if="posterImg" class="poster-share__content--img" mode="aspectFit" :src="posterImg" > <!-- 分享海報canvas繪制部分 --> <canvas class="poster-share__content--cvs" :canvas-id="canvasId" ></canvas> </div></template>
2、樣式部分
該業(yè)務(wù)場景下,不能讓用戶看到畫布,但是設(shè)置canvas的display為none將不能進(jìn)行繪制,會報如下錯誤,導(dǎo)致繪制失敗。
??
實現(xiàn)方式:采用定位的方式,將canvas定位到可視區(qū)域外,具體代碼如下。
.poster-share__content { position: absolute; right: -9999px; top: -9999px; width: 560px; height: 852px; opacity: 0; z-index: -1; &--img { width: 100%; height: 100%; } &--cvs { width: 100%; height: 100%; }}
3、核心js部分
開始寫核心實現(xiàn)啦~
父組件傳參控制子組件是否開始繪制,子組件繪制完成后通知父組件改變狀態(tài)。
name: 'CpPosterShare', model: { prop: 'value', event: 'update:value', }, props: { value: { type: Boolean, default: false, }, config: { type: Object, default: () => ({}), }, }, data () { return { isDraw: false, // 是否開始繪制海報 posterImg: '', // 生成的海報圖片地址 canvasId: `canvasId${ Math.random() }`, screenWidth: null, // 屏幕寬度 } }, watch: { value: { handler (val) { this.isDraw = val }, immediate: true, }, isDraw (val) { this.$emit('update:value', val) if (val) { this.init() } }, },
首先,我們做的是一個小程序,將圖片放在小程序源碼中會加大包的體積,需要從網(wǎng)絡(luò)上下載圖片,因此需要封裝一個公共的方法來獲取圖片的信息。Taro提供getImageInfo方法返回圖片的原始寬高、本地路徑等信息。
// 加載圖片loadImg (src) { return newPromise((resolve, reject) => { Taro.getImageInfo({ src, }).then((res) => { resolve({ ...res }) }).catch((err) => { reject(err) }) })}
該業(yè)務(wù)場景中涉及繪制多張圖片,包括背景圖片和二維碼圖片,需要將多張圖片都load完成后才能開始繪制。
const promiseParams = [this.loadImg(BgImage), this.loadImg(QRcode)]const promiseAll = Promise.all(promiseParams.map((item) =>item.catch(() =>null)))promiseAll.then((res) => { this.draw(res)}).catch((err) => { console.log(err)})
開始繪制啦~
創(chuàng)建canvas繪圖上下文CanvasContext對象,調(diào)用Taro提供的方法Taro.createCanvasContext(canvasId)繪制背景圖、繪制價格、繪制二維碼,這里就不一一贅述了。全部繪制完成后,將畫布中的內(nèi)容導(dǎo)出生成圖片,Taro提供了canvasToTempFilePath方法,需要在draw()回調(diào)中調(diào)用才能保證圖片導(dǎo)出成功,返回生成圖片的臨時路徑。
ctx.draw(false, () => { Taro.canvasToTempFilePath({ canvasId:this.canvasId, }).then((res) => { this.posterImg = res.tempFilePath // 喚起分享菜單 this.showShareImageMenu() }).catch((err) => { console.log('海報生成失敗', err) Taro.showToast({ title: '海報生成失敗', icon: 'error', }) }).finally(() => { Taro.hideLoading() this.isDraw = false })})
本地圖片生成成功后,喚起微信提供的分享菜單彈窗,可以將圖片發(fā)送給朋友、收藏、保存到相冊。Taro提供showShareImageMenu方法喚起分享菜單彈窗,入?yún)楸镜貓D片路徑。
showShareImageMenu () { if (Taro.showShareImageMenu) { Taro.showShareImageMenu({ path:this.posterImg, }).then().catch((err) => { console.log(err) const { errMsg } = err // 取消操作 errMsg === 'showShareImageMenu:fail cancel' // 拒絕授權(quán) errMsg: "showShareImageMenu:fail auth deny" if (errMsg === 'showShareImageMenu:fail auth deny') { authorize({ scope:'writePhotosAlbum', showModal:true, authName:'保存圖片到相冊', success: () => { this.downloadImg() }, }) } }).finally(() => { this.isDraw = false }) } else { Taro.showToast({ title:'小程序版本不支持該功能', icon:'error', }) }}
用戶點擊發(fā)送給朋友,會調(diào)起微信對話框,將生成的海報圖片粘貼分享給朋友;
點擊收藏,會將海報圖片添加到收藏列表中,方便下次查看;
點擊保存到相冊,會喚起保存圖片授權(quán)彈窗,用戶點擊允許,會將海報圖片保存在本地相冊中。
??
如果用戶在保存圖片授權(quán)彈窗中第一次點擊拒絕,之后再次點擊分享下載時,需要有授權(quán)提示彈窗,提示用戶是否打開設(shè)置去授權(quán),具體展示如下。
Taro提供Taro.openSetting方法調(diào)起小程序設(shè)置頁面,用戶開啟“添加到相冊”授權(quán)后成功后,調(diào)用Taro提供的下載圖片的方法Taro.saveImageToPhotosAlbum將圖片下載到本地。
授權(quán)提示彈窗 | 設(shè)置頁面 | 下載提示 |
其中判斷用戶是否開啟授權(quán)的方法具體實現(xiàn)如下:
/** * 權(quán)限獲取流程 * @param scope 權(quán)限英文名稱 * @param success 授權(quán)成功的回調(diào) * @param fail 授權(quán)失敗的回調(diào) * @param showModal 授權(quán)失敗是否展示對話框提示 * @param authName 授權(quán)失敗是否展示對話框提示展示的授權(quán)名稱 * // 例子:開啟用戶的相冊權(quán)限 authorize({ scope: 'writePhotosAlbum', showModal: true, authName: '保存圖片到相冊', success () { console.log('授權(quán)成功') }, })*/export async function authorize (options) { const { scope, success, fail, showModal = false, authName = '', } = options try { const scopeName = `scope.${ scope }` const auth = await Taro.getSetting() if (!auth.authSetting[scopeName]) { Taro.authorize({ scope: scopeName }).then((res) => { if (res.errMsg === 'authorize:ok' && success) success() }, () => { if (showModal && authName) { Taro.showModal({ title: '授權(quán)提示', content: `您拒絕了${ authName }權(quán)限,是否打開設(shè)置去授權(quán)?`, }).then((res) => { if (res.confirm) { Taro.openSetting().then((res2) => { if (res2.authSetting[scopeName] && success) { success() } else if (fail) { fail() } }) } else { fail && fail() } }).catch((res) => { fail && fail(res) }) } else { fail && fail() } }) } else { success && success() } } catch (err) { fail && fail(err) }}
至此,具體實現(xiàn)完結(jié)撒花~ 可以將組件用到頁面中了
組件引用
<poster-share v-model="draw" // 是否開始繪制海報海報 config="config" // 海報配置信息/>
問題記錄
在開發(fā)過程中遇到了一些問題,記錄一下
現(xiàn)象:點擊分享,生成canvas圖片。開發(fā)者工具上每次都正常,ios機每次都正常,部分安卓機每次都正常,部分安卓機,點擊分享之后取消,操作多次,有幾次會生成圖片失敗
報錯信息:"errMsg": "canvasToTempFilePath:fail :create bitmap failed"
錯誤定位解決:canvas需要一直顯示,不能有display:none的情況
作者:京東零售 張夢雨
內(nèi)容來源:京東云開發(fā)者社區(qū)
版權(quán)聲明:本文內(nèi)容由互聯(lián)網(wǎng)用戶自發(fā)貢獻(xiàn),該文觀點僅代表作者本人。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如發(fā)現(xiàn)本站有涉嫌抄襲侵權(quán)/違法違規(guī)的內(nèi)容, 請發(fā)送郵件至 舉報,一經(jīng)查實,本站將立刻刪除。