用小程式·雲開發打造功能全面的部落格小程式丨實戰

  • 2019 年 10 月 3 日
  • 筆記

用小程式·雲開發將部落格小程式常用功能「一網打盡」

本文介紹mini部落格小程式的詳情頁的功能按鈕如何實現,具體包括評論、點贊、收藏和海報功能,這裡記錄下整個實現過程和實際編碼中的一些坑。

評論、點贊、收藏功能

實現思路

實現文章的一些操作功能,最主要的還是評論,這是作者和讀者之間溝通的橋樑,評論功能的衍生無非是細化作者和讀者之間的互動,或者增加文章的傳播,所以在動手開發時需要思考下你期望實現哪些功能,並對應功能進行細化。

我一般的經驗是,先在腦子裡過一遍需要的功能和大致流程,然後在筆記稍微畫下「最最基礎的原型,相當於產品的角色」。

然後就開始直接開始搭建頁面和簡單的交互「使用假數據,優先完成頁面」,在構造頁面的時候其實也能夠補充最初想法上一些流程上的缺陷,這樣在設計後端和資料庫結構的時候可以補上,整體下來也基本比較完善了。

回頭看我的小程式的需求,首先肯定是操作,在文章底部需要有個操作欄,用於發送點評和其他一些操作,在參考了一些同類型的小程式之後,逐步實現自己的一套風格,樣式截圖如下:

在有了功能之後,點評的數據需要有地方展示「通常是文章底部」,然後就有了文章底部的評論列表,樣式如下:

既然有點贊和收藏的功能按鈕,是否用戶需要看下我點贊和收藏的文章列表呢,所以在「我的」中就有相應的列表,樣式如下:

image

到這裡,最最基礎的功能基本差不多,接下來就要看後端是否能支援這些頁面了「主要就是數據的保存和展示了」

對於評論來說,肯定需要一個集合用於保存用戶的評論,而對於用戶的喜歡和收藏也需要一個集合來進行保存。

所以根據頁面我們就可以設計mini_comments和mini_posts_related兩個集合。前者用於保存評論數據,後者用戶保存用戶操作與文章之間的關聯。

剩下的工作就是變現了,無非就是頁面交互和數據的增刪改查了。

細節點解析

關於評論數量

目前在文章的集合中有個totalComments這個屬性,當這篇文章每新增一個評論時,需要加1。

最初在寫這個的時候,每次都是先查再更新,兩段式,原程式碼如下:

  let count=post.totalComments+1;    let result =await db.collection('mini_posts').doc(event.commentContent.postId).update({    ​    data: {    ​      totalComments: count    ​    }      });  

後來看文檔發現,可以使用db.command.inc這個指令,無需再查一遍,直接可對原欄位加1,還能保證原子性。程式碼如下:

  const _ = db.command    let result = db.collection('mini_posts').doc(event.commentContent.postId).update({    ​    data: {    ​      totalComments: _.inc(1)    ​    }      });  

關於新增子評論

需要實現在某個評論下進行回復。

在交互上,點擊評論者的昵稱或頭像時,觸發相應的點擊事件,在事件中去記錄相應的評論ID及必要數據,同時去設置焦點到評論框內:

   /**      * 點擊評論內容回復      */      focusComment: function (e) {    ​    let that = this;    ​    let name = e.currentTarget.dataset.name;    ​    let commentId = e.currentTarget.dataset.id;    ​    let openId = e.currentTarget.dataset.openid;        ​    that.setData({    ​      commentId: commentId,    ​      placeholder: "回復" + name + ":",    ​      focus: true,    ​      toName: name,    ​      toOpenId: openId    ​    });      },  

利用雲開發新增子評論時可以使用db.command.push來進行操作「更新指令,對一個值為數組的欄位,往數組尾部添加一個或多個值」,往子評論集合中新增:

  /**     * 新增子評論     * @param {} event     */    async function addPostChildComment(event) {          let task = db.collection('mini_posts').doc(event.postId).update({    ​    data: {    ​      totalComments: _.inc(1)    ​    }      });      await db.collection('mini_comments').doc(event.id).update({    ​    data: {    ​      childComment: _.push(event.comments)    ​    }      })      await task;    }  

關於判斷是否已收藏

在文章第一次載入時,我們需要判斷下該用戶是否有對該文章有相關操作,如果有相應的收藏和點贊操作,在初始化時需要更新相應的功能圖標,核心程式碼如下:

    /**       * 獲取收藏和喜歡的狀態       */      getPostRelated: async function (blogId) {    ​    let where = {    ​      postId: blogId,    ​      openId: app.globalData.openid    ​    }    ​    let postRelated = await api.getPostRelated(where, 1);    ​    let that = this;    ​    for (var item of postRelated.data) {    ​      if (config.postRelatedType.COLLECTION === item.type) {    ​        that.setData({    ​          collection: { status: true, text: "已收藏", icon: "favorfill" }    ​        })    ​        continue;    ​      }    ​      if (config.postRelatedType.ZAN === item.type) {    ​        that.setData({    ​          zan: { status: true, text: "已贊", icon: "appreciatefill" }    ​        })    ​        continue;    ​      }    ​    }      },  

至於其他一些交互細節和程式碼細節,可以自行閱讀源碼去體會,如果有任何疑問或者有更好的實現方式,也可以與我溝通。

海報功能

交代些背景

其實在最早之前的小程式中已經實現了一次,具體可以參考利用雲開發優化部落格小程式(三)——生成海報功能,主要還是使用原生的cavans進行組裝,原本想程式碼copy過來改改就行了,但總覺得原來的程式碼寫的不是特別好。

於是想看看是否有現成的輪子可以利用,果然發現了wxa-plugin-canvas這款組件,通過非常簡單的配置就可以生成精美的海報。

小程式使用npm

在總結生成海報功能之前還是有必要記錄下小程式npm的使用,避免一些不必要的坑。

考慮到小程式本身的大小限制,使用npm的方式是最佳的。

原因是根據官方文檔介紹,小程式 npm 包里只有構建文件生成目錄會被算入小程式包的佔用空間,上傳小程式程式碼時也只會上傳該目錄的程式碼。這樣大大減少了上傳的程式碼體積。

下面簡單介紹下小程式端如何使用npm的「其實根據官方文檔按照步驟就可以了」。

以我目前小程式的路徑為例,在/miniprogram新增文件夾node_modules,在命令行指向到/miniprogram目錄下:

image

通過命令進行安裝:

  npm install wxa-plugin-canvas --production  

安裝成功後,即可在小程式開發工具中進行構建,構建前需要勾選使用 npm 模組

image

然後點擊開發者工具中的菜單欄:工具 --> 構建 npm即可:

image

構建完成後會生成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();    ​       });    ​    }    })  

核心程式碼解析

海報需要的數據

先來看看分享海報的整體結構:

image

首先需要確認海報的構成需要哪些數據,在調用組件前先獲取好相應的數據。

在我設計的海報中主要包含三塊內容,用戶的資訊(頭像和昵稱),文章資訊(首圖,標題,簡介)和最重要的文章的小程式碼。

用戶資訊和文章資訊其實比較簡單,在小程式的詳情頁兩者數據都有,但這裡有兩個問題點需要注意下。

第一個是域名問題,在畫布中使用到的圖片都需要配置域名,頭像的域名和公眾號文章首圖的域名

  https://mmbiz.qpic.cn    https://wx.qlogo.cn  

第二個是公眾號首圖的問題,公眾號素材列表返回的圖片url其實是http的,但小程式規定綁定的域名必須是https的,當時比較無奈,後來嘗試改用https訪問首圖的url也可以,不幸中的萬幸,所以在使用首圖地址時進行替換下:

  imageUrl = imageUrl.replace('http://', 'https://')  

最後就是文章的小程式碼了,需要利用小程式的getUnlimited的api,具體可以參考官方文檔,目前已經提供了雲調用的方式「無需獲取access_token」,調用起來還是比較簡單的。

原本打算在文章同步的時候「adminService」直接生成對應文章的小程式碼,程式碼寫完後本地調試可以,但上傳至雲端後測試發現一直報錯,逛了輪胎才知道原來不支援,同時觸發器也不支援雲調用,所以這個計劃泡湯了,我在程式碼中打了TODO。

image

既然這樣,那就在生成海報的時候進行生成,同時生成後直接上傳至雲存儲,將對應的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('獲取保存到相冊許可權失敗');    ​                        }    ​                      }    ​                    })        ​                  }    ​                });    ​              }    ​            }    ​          })    ​        }    ​      }    ​    });      },  

體驗總結

  • 有好的開源組件可以充分利用,避免重複造輪子,有機會也可以學習下別人的實現方式。

  • 多看看文檔,其實小程式的文檔真的挺詳細的。

  • 這裡主要想分享實現一個功能實現的過程,有想法的時候如何一步步去成功實現。

  • 小程式本身不難,相應的文檔也很詳細,但是組裝的過程和邏輯的實現需要自身去思考和體會。多看看文檔,其實小程式的文檔真的挺詳細的。

  • 如果你的想法和流程都非常清晰,但還是沒辦法實現你的預期功能,那我建議你先放放,先把html,css,javascript熟悉下,再看幾遍小程式的文檔,也許你當時面臨的問題就不再是問題了。

源碼鏈接

https://github.com/TencentCloudBase/Good-practice-tutorial-recommended

如果你有關於使用雲開發CloudBase相關的技術故事/技術實戰經驗想要跟大家分享,歡迎留言聯繫我們哦~比心!

Tags: