開發筆記:使用 mpvue 開發鬥圖小程式

表示很不蛋定發表於2019-02-27

初衷

之前用過 wepy 框架寫了個小程式 GitHub - yshkk/shanbay-mina: 基於 wepy 框架的 “扇貝閱讀” 微信小程式,感覺寫法上類似 vue,但不那麼徹底。現在美團點評釋出的 mpvue 支援開發者可以用 vue 的語法開發微信小程式,正好有強需求需要一個鬥圖小程式,所以就嘗試了下。

專案地址

GitHub - yshkk/bqb-mpvue: 基於 mpvue 的表情包鬥圖微信小程式

掃碼體驗

開發筆記:使用 mpvue 開發鬥圖小程式

截圖

開發筆記:使用 mpvue 開發鬥圖小程式

開發細節和坑

使用 iView Weapp 元件庫

相關程式碼 pages/index/main.js 第 8 行

將元件庫的 dist 目錄拷貝到自己專案 static 目錄,然後在需要用到元件的頁面配置 usingComponents 即可。開發期間可能對元件的樣式不太滿意,或者一些蜜汁問題(比如 input 下邊框突然消失 issue),要改的話方式非常詭異 相關 issue,所以粗暴點的方式就是直接改元件庫裡的 wxss 檔案。

v-show 和 v-model 不好使

相關程式碼 pages/index/index.vue 第 4 行

關於 v-show 相關 issue,所以只能用 v-if 替代。使用 v-if 會銷燬不顯示的元件,但有個場景是期望保留原來的元件,因此只能曲線救國在元件外層包一個 < view > 使用 :style="{display?condition?'block':'none'}" 的方式(其實最好是用 keep-alive 的方法,可惜 mpvue 不支援)。

v-model 就很奇怪了,好像 input 不能雙向繫結,原因是自定義元件就沒有支援 v-model,所以得手動 update data。同理使用元件庫 input 後不能使用 v-focus。(相關 issue)

模板語法裡不能呼叫 methods 方法

相關程式碼 components/homppage.vue 第 52 行

可以說是血坑了,一直以為我使用姿勢有誤,費了好長時間。後來才從 articles / 美團小程式框架 mpvue 蹲坑指南. md at master · noahlam/articles · GitHub 看到原來這是 mpvue 不支援。 當時的場景是這樣的: 在圖片列表裡,給被使用者 “收藏” 過的圖片加個額外的 className,該 className 可以給圖片加個粉色邊框,這樣就能在圖片列表中一眼看到哪些是被收藏過的。data 裡有一個表示所有圖片的陣列 imageList 和一個表示收藏列表的陣列 favoriteList 。起初的寫法是

<image v-for="img in imageList" :src="img.url" :class="isFavorite(img.url)?'image-favorite':'image'"
複製程式碼

其中 isFavorite 是在 methods 裡的一個方法,判斷當前圖片 url 是否在 favoriteList 裡。然而這樣寫一直不 work,後來只能換個方案:在 computed 裡跟據 imageListfavoriteList 計算出 一個叫 imageListWithFavorite 的陣列,遍歷這個資料即可? 雖然很醜陋但是還能用。

將使用者收藏同步到本地儲存

相關程式碼 components/homppage.vue 第 63 行

使用者收藏的表情會放到微信提供的 storage,類似瀏覽器的 localstorage,這樣在關閉小程式以後下次來還能看到自己的收藏,因此在元件需要 watch favoriteList 的變更並呼叫 wx.setStorage 方法。但是不知為何直接 watch favoriteList 並不會觸發相應函式,而 watch ‘favoriteList.length’就能觸發,希望有大佬能指點下。

watch: {
    'favoriteList.length': {
      // 將變化更新到本地儲存
      handler: function (val, oldval) {
        this.updateStorage({method: val > oldval ? 'ADD' : 'DELETE'})
      }
    }
  }
複製程式碼

表情包圖片製作

相關程式碼 pages/maker/index.vue

思路是初始化一個 canvas,將表情模版(一張圖片,url 從跳轉過來的頁面的 query 裡取得)繪製到 canvas 上,使用者打字 / 設定顏色字型 的時候呼叫 updateCanvas 。最後呼叫 wx.canvasToTempFilePath 方法輸出成圖片。 關鍵程式碼如下

  ctx = wx.createCanvasContext('maker') // 選擇當前 canvas
  ...
	updateCanvas () {
      ctx.drawImage(this.path, 0, 0, 300, 300) //path 為當前表情包的路徑
      ctx.setTextAlign('center') // 必須每次在 updateCanvas 重新設定,否則模擬器上生效但真機下不會生效
      ctx.setFontSize(this.fontSize)
      ctx.setFillStyle(this.currentColor)
      ctx.fillText(this.txt, this.x, this.y)
      ctx.draw()
    },
複製程式碼

有幾個小坑:

  • 將圖片繪製到 canvas 時指定的圖片不能是一個遠端圖床的連結,必須先本地下載下來(呼叫 wx.getImageInfo 獲取圖片,得到本地一個臨時 path)才能繪製。
  • canvas 指定的大小單位是 px,而用 css 控制的單位是 rpx(mpvue 用了 px2rpx-loader ,就算在 css 裡寫成 px 也會被編譯成 rpx)。
  • 小程式 canvas 的 saverestore 功能在這裡很雞肋,每次都需要完全重繪一次。特別是使用者拖動文字更新文字座標的功能,touchmove 事件一直觸發,就一直更新 canvas,小程式裡沒有 requestAnimationFrame 的方法,所以就自己得~~ 從網上找~~ 封裝一個,在拖動時起到節流的效果。
  • canvas 輸出的圖片只支援 jpg 或者 png,因此即使用 gif 圖的模版也只能生成靜態的表情包,殘念。

總結

大體上使用 mpvue 的體驗還是挺好的。mpvue 和 wepy 的寫法上比較類似,mpvue 對 vue 開發者來說更友好容易上手,wepy 更接近於原生小程式。雖然框架的出現遮蔽了一些原生小程式寫起來很醜陋的地方,但是不管用什麼框架,原生小程式的文件還是需要掌握的,有一大堆的坑等著要踩,有時候不得不從編譯出的檔案裡面找原因。

相關文章