微信小程式深度解析

GitChat的部落格發表於2018-04-12

內容簡介

從小程式誕生伊始,就有很多人開始研習其機理與特點,從原始碼或整體架構的角度已經有很多不錯的文章會令人受益。但理論是一回事,真正理解小程式,還需要實踐,才能進一步理解其背後的想法,與已有平臺的異同,以及如何去適應它,做出更有趣的小程式。

雖然小程式釋出的時間還不長,但其目前的使用者體驗、開發者體驗都已經達到比較優秀的水平,而且微信團隊對小程式長期保持著積極推進的態度,我們可以預見小程式生態在未來會越來越蓬勃。無論是從商業角度考量,還是從技術角度來看,小程式都值得大家去了解、學習和嘗試。

本書內容

微信小程式的程式設計模式

“輕芒小程式+”是由輕芒團隊提出的小程式解決方案,它將替內容創業者免費搭建屬於自己的微信小程式。在進行“輕芒小程式+”和其他小程式應用開發的過程中,本文作者與其團隊對當前正火熱的小程式開發有了更為深度的理解與認識,進而有了本文。

從小程式誕生伊始,就有很多人開始研習其機理與特點,從原始碼或整體架構的角度已經有很多不錯的文章會令人受益。但理論是一回事,真正理解小程式,還需要實踐,才能進一步理解其背後的想法,與已有平臺的異同,以及如何去適應它,做出更有趣的小程式。

理解開發平臺的特性,一個不錯的角度就是從程式設計模式入手,看在這個平臺上開發,需要如何書寫和組織自己的程式碼,進而搞清楚三個問題:

  1. 資料如何獲取;
  2. 介面如何呈現;
  3. 互動如何傳導。

換而言之,就是從 MVC(Model-View-Controller)的視角去拆解這個平臺的特性,從而理解其開發有何特點。

資料如何獲取

程式的本質,可說就是資料的呈現和加工。所以,看一個客戶端開發平臺的基本能力,首先就要看能把哪些資料放在上面處理,有哪些侷限?如果缺少了必要的資料獲取方式,那對於開發者而言,巧婦也難為無米之炊。

從這點看,小程式提供的資料獲取方式非常豐富,大概涵蓋:

通過 HTTPS 請求去服務端獲取資料。支援 HTTPS 是最基本的,小程式對 HTTPS 有限制,除了要求通訊協議是 HTTPS,出現的域名必須提前預設之外,還將應用層協議限定到了 JSON 格式下。這一點,可能比任何一個已有客戶端平臺都更為嚴苛。站在小程式的平臺角度來看,通過這樣的協議規定,對應用中流動的資料有了更強的管控能力;而對於開發者而言,則需要花些時間去調整自己的服務協議以便適應小程式的要求。

可以在本地檔案系統上存取資料。小程式提供了豐富的 API 供開發者在手機系統上存取檔案。可用本地檔案來做快取、狀態記憶等,為開發提供了便利。

可以讀寫裝置中的一部分資訊。小程式開放了一些 API,幫助開發者獲得裝置上的基本資訊,比如手機型號、螢幕尺寸、網路狀態等。較為有價值的是可以選擇獲取手機上的圖片等多媒體檔案,這給做影象應用提供了可能;並且,它還提供了羅盤、重力感應器、地理位置等資訊,對開發者理解使用者所處的環境大有裨益。

從上面的介紹不難看出,小程式中的資料獲取方式,和一般瀏覽器提供的相仿(也就是和 HTML5 應用能獲取的資訊),比原生的客戶端更侷限一些,但對於絕大多數的應用而言足夠用了。

除此之外,小程式提供了微信生態中的一些資料,比如賬號資訊等。這對於微信龐大的生態而言,只是非常小的一部分資料,但卻是開發小程式應用中最值得利用的資料。

舉個例子,在其他平臺上,如果想要獲取微信的賬號資訊,需要通過一次使用者授權。假如使用者暫時不想提供,則會使程式呈現“未登入”狀態,給整個服務的展開帶來困難。而在小程式中,只要使用者點開,就意味著完成了授權,開發者可以直接讀取到小程式的賬號資訊,並同步到自己的服務端作為該使用者的身份標識,從而實現“始終登入”的狀態,使得後續服務可以更好地提供。

一份可行的示例如下:

// 先呼叫登入介面,獲得請求碼wx.login({    success: function (res) {    // 獲取到請求碼,繼續請求使用者的基本資訊        var code = res.code        wx.getUserInfo({        success: function (res) {                // 獲取到//了加密的使用者資訊,去服務端解密並儲存                var userData = res.encryptedData                var iv = res.iv                wx.request({                    url: 'https://my_account/...',                    data: {                     code: code,         user_data: userData,               iv: iv                   },                    success: function(res) {        // 在伺服器上,解析並生成自己的賬號驗證資訊 var user = res.data.uservar token = res.data.token// 並且還可以存在本地儲存上,供下次開啟使用    wx.setStorage({        key: 'my_token',        data: token                      })             }                  })        }            })          }       });

介面如何呈現

小程式剛釋出的時候,一片人開始驚呼 HTML5 的時代就要到來了,因為小程式在介面層使用了 HTML/CSS/JavaScript 這套 HTML5 的技術棧。但很快,隨著聰明的程式設計師們對小程式的理解進一步加深,就發現小程式所說的 HTML/CSS/JavaScript 和 HTML5 中的完全不是一回事,其差異基本等同於 Java 和 JavaScript。

在小程式中,和 HTML 對應的是 WXML,保留下來的只有 HTML 的概念,而傳統的<div><a>標籤都完全被拋棄了。和 Facebook 的 React 類似,小程式引入了自己的 HTML 標籤,它和<article><section>這樣的語義標籤不同,小程式中的標籤更像是傳統客戶端開發中的元件(或者叫控制元件),每個元件都有自己背後的職能和使用方式。比如:如果需要展示圖片,就只能用<image>標籤,其他的都無法承載。而如果需要提供可選的文字,則只能使用<text>標籤等。

這樣的方式帶來最大的問題就是傳統的 HTML 頁面都無法在小程式中呈現(而小程式正好,沒提供類似 WebView 的客戶端控制元件)。比如有大量的內容網站,其文章內容都是儲存為一個 HTML 片段,無法直接呈現在小程式中。如果需要展示,一個思路是構建中間服務,將 HTML 轉譯成一種更簡單利於渲染的中間格式資料,然後,在小程式端把中間格式的資料轉換成小程式的標籤進行呈現。我們在做“輕芒生活”的時候,正好設計並實現了一個轉義服務,將任意一個 HTML 頁面轉換成中間格式(內部名是 RAML),解決了內容性 HTML 頁在小程式上的呈現問題,如圖1所示。

enter image description here

圖1 在小程式中呈現HTML內容頁

和 HTML 相比,小程式的 WXSS 算是比較完整地保留了 CSS 的特徵,這一點還蠻出乎意料。WXSS 在語義上最大的不同,一是在於它支援了相對尺寸單位 rpx(responsive pixel),每 750rpx 等價於當前裝置的螢幕寬度,它的引入,把那種繁複的螢幕尺寸適配變得簡單了不少。而和 CSS 的另一個不同是它更像傳統控制元件樣式用法,不支援 CSS3 那麼多的選擇器,使用中更多的是一個控制元件一個 class。

小程式中雖然支援 ES6 標準的 JavaScript,但視窗級的 JavaScript 卻完全被廢棄掉了,開發者無法用 JavaScript 去呼叫 window、document 物件來修改介面元素完成邏輯。小程式中的 JavaScript 其實直接對應 Node.js 的用法,用來完成後臺業務邏輯,而不是直接控制互動。小程式的這個設計,使其可以用到 Virtual Dom 的方式來渲染介面,讓介面資料更新時的效能優化成為可能,但付出的代價就是少了視窗級 JavaScript 的那層膠水黏合,使得很多功能的開發變得極其呆板和繁複。

互動如何傳導

所謂互動的傳導,是當使用者和介面發生互動時,平臺框架通過何種方式告訴業務層,並將處理後的變化呈現回互動介面上。如果把 WXSS + WXML 繪製的頁面看成“前端”,把 JavaScript 撰寫的業務邏輯看成“後端”,你會發現,小程式的前後端互動特別像 Web 1.0 的模式,前端把互動行為封裝成事件(event)傳送到後端,後端處理完成後,通過 setData 方法將資料回傳到前端,如圖2所示。

enter image description here

圖2 小程式的互動傳導

小程式提供的 Events,基礎的有類似單擊、長按、觸控、滑動等,對於視訊播放器等控制元件,還有監聽播放、暫停等。這些事件比較基礎,沒有更高階的手勢、多點觸控等相關事件,但也還足夠讓開發者具體瞭解使用者的輸入,進而做出響應。

而小程式給介面響應的唯一方式,是通過 Page 中的 setData API 對介面上的資料進行更新,小程式會比較兩次呼叫期間資料的變化,來決策需要更新哪部分的互動介面。

舉個實際的例子,假設開發者需要做一個滑動切換頁面的效果,在小程式中該如何實現?首先,是將變數資料引入渲染頁面:

<view class="page" id="current-page" style="left:{{distance}}rpx;" bindtouchstart="movePage" bindtouchcancel="movePage" bindtouchmove="movePage" bindtouchend="movePage"></view>

可以看到,distance 是一個模版引數,它初始值為0,表示移動的距離。通過 bindtouchstart 等函式繫結上 JavaScript 的方法,將事件回傳。

movePage: function(event) {    var status = {    needUpdate: false,    distance: 0    }    // 處理各種事件,計算是否需要重新整理,和移//動方向    if ("touchstart" === event.type) {    // 開始計算移動    ...    } else if ("touchend" === event.type) {    // 判定移動的距離是否足夠.    ...    } else if ("touchcancel" === event.type) {    // 被打斷就算了.    ...    } else if ("touchmove" === event.type) {    // 計算移動距離    ...    }    // 根據移動的距離,來更新介面    if (status.needUpdate) {    this.setData({    distance: status.distance        })    }}

而在 JavaScript 一端,則捕獲事件、計算偏移量,然後將新的偏移量送到前端介面。

從這裡可以看到,小程式的互動是典型的單向模式,前端回傳事件,資料單向地推到前端,而不是通過類似“變數”、“狀態”等方式來告知。這樣的模式下,開發者對介面變化的控制往往不可能太精準,整個核心都依賴於小程式對兩次資料變化的 diff 計算,這將會最終影響整個互動的效能。

小程式開發模式的特點

至此,我們可以來總結一下小程式開發的一些特點了。整體來看,小程式是借了 HTML5 的技術棧,行了傳統客戶端開發的模式,這一點和 React 等平臺會比較相近,可以視為 HTML5 的一個新分支。

從設計思路看,小程式做了大量的“限制”,最大的限制是開發者其實無法通過 JavaScript 這樣的程式語言直接對介面進行控制,而是通過資料驅動來間接實現。這對於缺少開發經驗的人而言,是有益的事情,因為降低了理解的門檻,但對於複雜的應用來說,這個模式開發起來比較呆板,往往是一個變化多處修改,增加了理解程式碼的成本。

開發小程式的坑

開發小程式的日子,也是一個踩坑的歷程。簡單總結,小程式中的坑大概來自這幾個方面:

Web 相容性。小程式引入了 HTML/CSS 作為技術棧,並在其基礎上進行了定製。很多開發中的問題都來自於“定製”,因為你並不知道哪部分是被定製,哪部分是被繼承了。比如,你用了一個 CSS 語法,發現並不生效,或者效果和瀏覽器中的不一樣,於是,只能換一個寫法,結果很有可能又會繼續發現,這個新的寫法可能效果也不對,於是只能繼續嘗試,如此反覆,可能會消耗大量的時間。

開發環境不穩定。小程式的開發,是基於微信自制的 IDE,但當下,IDE 的穩定性、易用性都非常差,時常出現 Bug,你以為是程式寫錯了,但其實,是 IDE 的 Bug,重啟一下 IDE,一切都迎刃而解了。於是,當你日後開發小程式時出現某種異樣,先重啟 IDE,再看問題還在不在,也許是種更節省時間的方式。

缺少真機除錯環境。小程式的執行時其實就是微信,微信幾乎沒提供任何真機上的除錯工具(也不能說完全沒有,有一個只能在真機上瞪著眼睛看的日誌框)。在模擬器中除錯好的程式,可能在真機上執行起來並不如預期。比如,我們碰到過真機上白屏、位置錯亂、動畫效果不對,以及 Android 上至今還不能執行等問題。這對於稍微複雜的程式而言,頗為夢魘,想做一些細粒度的調整和優化,基本只能靠猜。

閉源且缺少學習資料。小程式整體上是閉源狀態(雖然模擬器和 IDE 部分可以通過反編譯來看),且缺少足夠的學習資料。如果一旦碰到控制元件如何使用、為什麼這麼用不對之類的問題,就只能靠不停地試來解決,也需要耗費大量時間。

簡而言之,作為一個新的開發平臺,微信小程式從本身的穩定性,以及配套的工具鏈上都不算完善。對於早期開發者而言,需要耗費額外的精力去嘗試和探索,但這也許就是一個新平臺的價值和代價吧。


範懷宇
輕芒聯合創始人,畢業於清華大學,前豌豆莢技術負責人,專注於移動開發十餘年,曾 出版《Android 開發精要》。愛研習好程式碼和設計,相信好的產品能改變生活,好閱讀樂分享。

微信小程式技術解讀
從《小睡眠》談微信小程式開發的實用技術與注意事項
《輕課》微信小程式踩坑歷險記
使用 Vue.js 開發小程式:解析前端框架 mpVue
微信開發深度解析之快取策略(上)
微信開發深度解析之快取策略(下)

閱讀全文: http://gitbook.cn/gitchat/geekbook/5a5eaf8edff55721bc1dcac1

相關文章