大衆點評點餐小程序開發經驗 - 邏輯層

做者介紹:潘逸飛,美團點評工程師,2年Web開發經驗,如今是美團點評點餐團隊的一員。javascript

本文接上期的大衆點評點餐小程序開發經驗 - 視圖層,本期想要和你們分享一下大衆點評點餐小程序開發中的邏輯層的經驗。html

與視圖層微信本身定義了一套與HTML對應的WXML和WXSS不一樣,小程序的邏輯層仍是使用javascript編寫的。不過與咱們普通的編寫js仍是有一些區別的。接下來我會根據實踐進行說明。邏輯層代碼結構爲前端

menu
├── menu.html
├── menu.js
├── menu.json
└── menu.less
app.jsjava

做爲邏輯層咱們只須要關注app.js和menu.js。node

App和Page

App

小程序提供了App方法來註冊整個小程序,在App方法裏咱們能夠傳入一個對象,指定小程序的生命週期函數以及自定義的函數或者數據。注意這個函數只能被調用一次。web

  • App
    • globalData
    • onLaunch
    • onShow
    • onHide
    • onError
    • 其餘自定義

如上所示,App擁有着4個生命週期函數,咱們能夠在launch的時候進行一些全局信息的獲取,好比用戶信息,門店信息等等,而後存入到全局數據中。這裏的數據能夠被每一個頁面訪問到。json

Page

小程序針對每一個頁面提供了Page的函數。整個邏輯層大部分的代碼都會寫在Page函數中,Page中承接着整個頁面的數據,生命週期函數,以及在視圖中綁定的事件的觸發函數,例如各點擊事件。整個Page函數容許的參數以下所示:小程序

  • Page
    • data
    • onload
    • onReady
    • onShow
    • onHide
    • onUnload
    • onPullDownRefresh
    • onReachBottom
    • onShareAppMessage
    • 其餘自定義函數

如上,Page函數由於是頁面級別的,因此擁有着更多的生命函數,會有下拉刷新事件,會有頁面到達底部的事件。這裏咱們須要區別好各個生命週期函數。onLoad只會在初始化的時候調用一次,onShow是每次打開頁面都會調用,onReady只有頁面初次渲染完成纔會被調用。onHide會在navigateTo(微信提供的跳轉API)或者底部tab切換時調用,onUnload會在redirectTo(微信提供的redirect的API)或者navigateBack(微信提供的回退的API)的時候調用。Page更具體的渲染過程能夠參考下面這張圖:後端

簡單描述下就是:視圖層和邏輯層同時進行初始化的操做:視圖層ready以後通知邏輯層發送數據;邏輯層執行onload和onShow方法,而後等待視圖層的通知,在接收到視圖層的通知以後發送數據給視圖層,而後繼續等待視圖層的通知。視圖層根據數據進行初次渲染後通知邏輯層渲染完畢,邏輯層調用onReady方法。而後後續的行爲邏輯層能夠經過再次發送數據從新渲染視圖層。微信小程序

Page的整個工做流程能夠參照下面的圖:


首先Page的data會被用於頁面的初始化渲染。而後用戶會在頁面上,也就是展現層觸發事件,好比咱們點餐的話,點擊了加菜按鈕。頁面監聽到這個事件以後,會觸發在Page函數中申明的自定義事件。而後根據具體狀況可能會調用微信的Api發起請求,根據請求的結果,咱們調用setData方法,來改變頁面的數據,小程序就會監聽到數據的改變而從新執行渲染的過程。這個寫過React的朋友,應該會很熟悉,React也是在Component裏面申明自定義方法,觸發後經過setState來從新渲染頁面。咱們以前的H5就是使用React寫的,因此邏輯層遷移到小程序的代價並非很大~

getApp和getCurrentPages

小程序內申明的變量和函數只在該文件內有效,不一樣的文件能夠申明相同名字的變量和函數,並不會相互影響。上面提到App內能夠設置全局數據。咱們在每一個Page裏面均可以經過全局函數getApp()來拿到全局的引用實例。而後就能夠訪問頁面的數據。好比咱們在購物車下完單以後回到菜單頁可能會須要進行菜單的刷新,咱們在購物車頁面就會調用getApp().data.menuRefresh = true,而後在菜單頁的onShow方法進行判斷,例如:

let app = getApp();
Page(
    requestMenu () {   
        //刷新菜單
    };
    onShow () {
        if (app.data.menuRefresh === true) {
            app.data.menuRefresh === false;
            this.requestMenu();
        }
    }
);複製代碼

在每一個Page內,咱們還能夠用getCurrentPages來獲取當前頁面棧的實例,數組形式,第一個元素爲首頁,最後一個元素爲當前頁面。頁面棧的表現狀況以下表所示:

路由方式 頁面棧表現
初始化 新頁面入棧
打開新頁面 新頁面入棧
頁面重定向 當前頁面出棧,新頁面入棧
頁面返回 頁面不斷出棧,直到目標返回頁,新頁面入棧
Tab切換 頁面所有出棧,只留下新的Tab頁面

注意咱們不能手動去嘗試修改頁面棧,咱們只能根據頁面棧,來分析是使用哪一種微信的API來跳頁面。這裏的跳轉API還會在下面進行講解。

模塊化

小程序是支持模塊化的,支持commonjs的模塊化寫法,也就是module.exports或者exports,這兩個的區別這裏就不細講了,不瞭解的能夠去看下nodejs的module那塊的文檔。小程序目前並不支持引入node_modules,也就是並不支持第三方的模塊,當咱們須要使用到外部的依賴的時候,建議直接將代碼拷貝到小程序的目錄中,而後經過相對路徑的require函數進行引入。

微信API

小程序做爲微信的一個重要功能,微信的框架提供了很是豐富的微信原生API,能夠方便的調起微信提供的能力,除了視圖層的一些原生組件外,還有一些功能性的API,如掃碼,定位,媒體播放,本地存儲以及支付功能等等。

咱們此次使用的較多的是經過微信發起網絡請求以及微信的數據存儲。

發請求

微信提供了wx.request來發起請求,注意這個方法發起的是HTTPS請求。因此在開發微信小程序以前,你們得先遷一下HTTPS~咱們本身在使用API的時候,還用了pinkie這個包將request包裝成了Promise的形式方便咱們使用。
比較重要的一點是微信的運行環境並非瀏覽器,並不提供cookie的功能。可是用戶咱們解決用戶鑑別的問題是帶上用戶的token,用戶的token是在用戶登陸的時候後端生成好了放置到App的全局數據中。

數據存儲

咱們大衆點評點餐頁面上有大量的菜單數據,這部分數據以前在H5上實現的時候用的是瀏覽器的localstorage。此次切換到微信的storage,代價很小,用了一下適配器模式,將微信的數據接口適配成咱們須要的接口就行了。這樣也是爲了之後的迭代慢慢讓H5與小程序使用同一套代碼。

導航

小程序爲了減小用戶使用的時候的困擾,規定了頁面路徑最多隻能有5層,因此咱們使用的時候得儘可能避免多層級的交互方式。


爲了方便調用,咱們此次管理頁面跳轉的時候本身封裝了一下函數,就是經過getCurrentPages來對頁面棧進行分析,而後選擇跳轉頁面的方式:

const app = getApp();
module.exports = function go2Page(opts) {
    if (!opts) return;
    if (!opts.url) return;
    let url = opts.url;
    //拿到當前的頁面棧
    const history = getCurrentPages();
    let path = url.split('?')
    let params;
    if (path.length === 2) {
        params = path[1];
    }
    let page = path[0].split('/').pop();
    let index = -1;
    for (var i = 0; i < history.length; i++) {
        let hPath = history[i].__route__;
        let hPage = hPath.split('/').pop();
        if (page == hPage) {
            index = i;
            break;
        }
    }
    if (index === -1) {
        //若是不存在這個頁面,直接跳轉
        wx.navigateTo({
            url: url
        });
    } else {
        //若是存在這個頁面,就回退回去
        if (params) {
            //query是處理下url參數的本身定義的函數
            params = query(params);
        }
        //將跳轉的頁面的參數保存到全局數據中,而後在頁面中能夠去拿取,store是本身申明的
        app.store(page, params);
        wx.navigateBack({
            delta: history.length - (index + 1)
        });
    }
}複製代碼

Tip

因爲小程序的框架並不是運行在瀏覽器中,因此javascript在web端的一些能力都沒法使用,除了上面提到的cookie,還有document,window等等。開發者全部代碼最終會被打包成一份javascript,在小程序啓動的時候運行,直到小程序銷燬。這一點相似於瀏覽器的ServiceWorker,因此邏輯層也稱之爲App Service。

本文時間爲2017-03-02,後續更新或修復請查看官方文檔

參考資料:
微信小程序開發者文檔


本文對你有幫助?歡迎掃碼加入前端學習小組微信羣:

相關文章
相關標籤/搜索