基於雲開發的小程式海報功能的實現
今天把文章詳情頁最後一個按鈕「生成海報」的功能開發完了,這裡介紹下實現思路和具體開發流程
交代些背景
其實在最早之前的小程式中已經實現了一次,具體可以參考 利用雲開發優化部落格小程式(三)——生成海報功能 ,主要還是使用原生的 cavans
進行組裝,原本想程式碼copy過來改改就行了,但總覺得原來的程式碼寫的不是特別好。
於是想看看是否有現成的輪子可以利用,果然發現了 wxa-plugin-canvas
這款元件,通過非常簡單的配置就可以生成精美的海報。
小程式使用npm
在總結生成海報功能之前還是有必要記錄下小程式npm的使用,避免一些不必要的坑。
考慮到小程式本身的大小限制,使用npm的方式是最佳的。
原因是根據官方文件介紹,小程式 npm 包裡只有構建檔案生成目錄會被算入小程式包的佔用空間,上傳小程式程式碼時也只會上傳該目錄的程式碼。這樣大大減少了上傳的程式碼體積。
下面簡單介紹下小程式端如何使用npm的「其實根據官方文件按照步驟就可以了」。
以我目前小程式的路徑為例,在 /miniprogram
新增資料夾 node_modules
,在命令列指向到 /miniprogram
目錄下:
通過命令進行安裝:
npm install wxa-plugin-canvas --production
安裝成功後,即可在小程式開發工具中進行構建,構建前需要勾選 使用 npm 模組
然後點選開發者工具中的選單欄:工具 --> 構建 npm即可:
構建完成後會生成miniprogram_npm目錄,到這裡,專案端基本就調通了。
wxa-plugin-canvas
在構建完之後,就可以正常使用wxa-plugin-canvas這個自定義元件,使用方式還是比較簡單的。
首先在你需要的頁面引入該元件:
{ "usingComponents": {"poster": "wxa-plugin-canvas/poster"} }
然後就可以在 wsml
中使用了:
<poster id="poster" hide-loading="{{false}}" preload="{{false}}" config="{{posterConfig}}" bind:success="onPosterSuccess" bind:fail="onPosterFail"></poster>
由於我們在生成海報前,需要非同步獲取一些用於海報的資料,所以我們採用非同步生成的海報方式。
需要引入該元件的 poster/poster.js
檔案,然後在程式碼中呼叫即可:
import Poster from '../../utils/poster'; Page({ /** * 非同步生成海報 */ onCreatePoster() { // setData配置資料 this.setData({ posterConfig: {...} }, () => { Poster.create(); }); } })
核心程式碼解析
海報需要的資料
先來看看分享海報的整體結構:
首先需要確認海報的構成需要哪些資料,在呼叫元件前先獲取好相應的資料。
在我設計的海報中主要包含三塊內容,使用者的資訊(頭像和暱稱),文章資訊(首圖,標題,簡介)和最重要的文章的小程式碼。
使用者資訊和文章資訊其實比較簡單,在小程式的詳情頁兩者資料都有,但這裡有兩個問題點需要注意下。
第一個是域名問題,在畫布中使用到的圖片都需要配置域名,頭像的域名和公眾號文章首圖的域名
https://mmbiz.qpic.cn https://wx.qlogo.cn
第二個是公眾號首圖的問題,公眾號素材列表返回的圖片url其實是 http
的,但小程式規定繫結的域名必須是 https
的,當時比較無奈,後來嘗試改用https訪問首圖的url也可以,不幸中的萬幸,所以在使用首圖地址時進行替換下:
imageUrl = imageUrl.replace('http://', 'https://')
最後就是文章的小程式碼了,需要利用小程式的 getUnlimited
的api,具體可以參考官方文件,目前已經提供了雲呼叫的方式「無需獲取access_token」,呼叫起來還是比較簡單的。
原本打算在文章同步的時候「adminService」直接生成對應文章的小程式碼,程式碼寫完後本地除錯可以,但上傳至雲端後測試發現一直報錯,逛了輪胎才知道原來不支援,同時觸發器也不支援雲呼叫,所以這個計劃泡湯了,我在程式碼中打了TODO。
既然這樣,那就在生成海報的時候進行生成,同時生成後直接上傳至雲端儲存,將對應的FileID儲存至文章集合中,這樣只用生成一次就可以一直使用了,具體程式碼如下:
/** * 新增文章二維碼 * @param {} event */ async function addPostQrCode(event) { let scene = 'timestamp=' + event.timestamp; let result = await cloud.openapi.wxacode.getUnlimited({ scene: scene, page: 'pages/detail/detail' }) if (result.errCode === 0) { let upload = await cloud.uploadFile({ cloudPath: event.postId + '.png', fileContent: result.buffer, }) await db.collection("mini_posts").doc(event.postId).update({ data: { qrCode: upload.fileID } }); let fileList = [upload.fileID] let resultUrl = await cloud.getTempFileURL({ fileList, }) return resultUrl.fileList } return [] }
但這裡有個尷尬的地方是,生成小程式碼的api中的 scene
引數最大長度是32,而文章id的長度已經是32了,無法根據文章id進行拼接跳轉頁面的路徑了,所以這裡暫時用了 mini_posts
集合中timestamp欄位「理論上也是唯一的」。
所以在詳情頁中也需要相容timestamp這個欄位。
海報圖片展示
海報圖片展示就比較簡單了,使用個彈窗,將生成好的海報圖片進行展示即可:
/** * 生成海報成功-回撥 * @param {} e */ onPosterSuccess(e) { const { detail } = e; this.setData({ posterImageUrl: detail, isShowPosterModal: true }) console.info(detail) },
儲存海報圖片
儲存圖片使用wx.saveImageToPhotosAlbum呼叫使用者相簿,這裡主要需要相容使用者拒絕相簿授權的一些列操作,具體程式碼如下:
/** * 儲存海報圖片 */ savePosterImage: function () { let that = this wx.saveImageToPhotosAlbum({ filePath: that.data.posterImageUrl, success(result) { console.log(result) wx.showModal({ title: '提示', content: '二維碼海報已存入手機相簿,趕快分享到朋友圈吧', showCancel: false, success: function (res) { that.setData({ isShowPosterModal: false, isShow: false }) } }) }, fail: function (err) { console.log(err); if (err.errMsg === "saveImageToPhotosAlbum:fail auth deny") { console.log("再次發起授權"); wx.showModal({ title: '使用者未授權', content: '如需儲存海報圖片到相簿,需獲取授權.是否在授權管理中選中“儲存到相簿”?', showCancel: true, success: function (res) { if (res.confirm) { console.log('使用者點選確定') wx.openSetting({ success: function success(res) { console.log('開啟設定', res.authSetting); wx.openSetting({ success(settingdata) { console.log(settingdata) if (settingdata.authSetting['scope.writePhotosAlbum']) { console.log('獲取儲存到相簿許可權成功'); } else { console.log('獲取儲存到相簿許可權失敗'); } } }) } }); } } }) } } }); },
總結
有好的開源元件可以充分利用,避免重複造輪子,有機會也可以學習下別人的實現方式。
多看看文件,其實小程式的文件真的挺詳細的。