去年年底,微信小程序的分包大小已經到達了 12M 大小,一方面說明小程序的確逐步爲開發者放開更大的權限,另外一方面也說明了對於某些小程序 8M 的大小已經不夠用了。我我的今年也是在開發一個 to B 小程序應用。這裏列舉一些跨頁面交互的場景。html
對於 B 端應用的業務需求來講,小程序開發的複雜度相對比網頁開發要複雜一些。一個是雙線程的處理機制問題,另外一個是頁面棧之間交互問題。前端
注: 筆者目前只須要開發微信小程序,爲了在小程序頁面中可使用 properties behaviors observers 等新功能,已經使用 Component 構造器來構造頁面。具體能夠參考微信小程序 Component 構造器。若是你也沒有多端開發的需求,建議嘗試使用,能夠獲得不錯的體驗。react
對於小程序在頁面中點擊觸發 wx.navigateTo 跳轉其餘頁面,中間會有一段時間的空白加載期(對於分包出去的頁面,空白期則會更長),可是這是小程序內部機制,沒有辦法進行優化。咱們只能眼睜睜的等待這段沒有意思的空白期過去。git
當考慮到跳轉頁面後的第一件事情即是取數邏輯,那麼咱們是否可以進行優化呢?答案是確定的。咱們沒有辦法直接在當前頁面取得數據以後再進行跳轉操做(這樣操做更很差),可是咱們卻能夠利用緩存當前的請求,詳情能夠參考我以前的博客文章 ——Promise對象 3 種妙用。github
代碼以下:小程序
const promiseCache = new Map() export function setCachePromise(key, promise) { promiseCache.set(key, promise) } export function getCachePromise(key) { // 根據key獲取當前的數據 const promise = promiseCache.get(key) // 用完刪除,目前只作中轉用途,也能夠添加其餘用途 promiseCache.delete(key) return promise }
作一份全局的 Map,而後利用 Map 緩存 promise 對象,在跳轉以前代碼爲:微信小程序
// 導入 setCachePromise 函數 Component({ methods: { getBookData(id) { const promise = // promise 請求 setCachePromise(`xxx:${id}`, promise) }, handleBookDetailShow(e) { const id = e.detail this.getBookData(id) wx.navigateTo({url: `xx/xx/x?id=${id}`}) } } })
而跳轉以後的代碼也以下所示:api
// 導入 getCachePromise 函數 Component({ properties: { id: Number }, lifetimes: { attached () { const id = this.data.id // 取得全局緩存的promise const bookPromise = getCachePromise(`xxx:${id}`) bookPromise.then((res) => { // 業務處理 }).catch(error => { // 錯誤處理 }) } }, methods: { getBook() { // 獲取數據,以便於 錯誤處理 上拉刷新 等操做 } } })
如此即可以同時處理取數和頁面加載的邏輯,固然,這個對於頁面有耦合性,不利於後續的刪除與修改。但考慮若是僅僅加在分包跳轉之間可能會有不錯的效果。promise
想要無侵入式,能夠進一步學習研究 微信小程序之提升應用速度小技巧 以及 wxpage 框架,同時考慮到不管是 ToC 仍是 ToC 用戶,都有可能存在硬件以及網絡環境等問題,該優化仍是很是值得的。緩存
固然微信小程序爲了減小冷啓動時間,提供了週期性更新 數據預拉取 功能。
注: 上面的 promiseCache 只做爲中轉的用途,不做爲緩存的用途,若是你考慮添加緩存,能夠參考我以前的博客文章—— 前端 api 請求緩存方案。
若是是 pc 端中進行交互,對於數據的 CRUD。例如在詳情頁面進行了數據的修改和刪除,返回列表時候就直接調取以前存儲的列表查詢條件再次查詢便可,而對於移動端這種下拉滾動的設計,就沒有辦法直接調用以前的查詢條件來進行搜索。
若是從列表頁面進入詳情頁面後,在詳情頁面只會進行添加或者修改操做。而後返回列表頁面。此時能夠提示用戶數據已經進行了修改,請用戶自行決定是否進行刷新操做。
如在編輯頁面修改了數據:
const app = getApp() component({ methods: { async handleSave() { //... app.globalData.xxxChanged = true //... } } })
列表界面:
const app = getApp() component({ pageLifetimes: { show() { this.confirmThenRefresh() } }, methods: { confirmThenRefresh() { // 檢查 globalData,若是當前沒有進行修改,直接返回 if(!app.globalData.xxxChanged) return wx.showModal({ // ... complete: () => { // 不管確認刷新與否,都把數據置爲 false app.globalData.xxxChanged = false } }) } } })
固然了,咱們也能夠利用 wx.setStorage 或者 getCurrentPage 獲取前面的頁面 setData 來進行數據通知,以便用戶進行頁面刷新。
若是僅僅只涉及到修改數據的前提下,咱們能夠選擇讓用戶進行刷新操做,可是若是針對於刪除操做而言,若是用戶選擇不進行刷新,而後用戶又不當心點擊到了已經被刪除的數據,就會發生錯誤。因此若是有刪除的需求,咱們最好在返回列表頁面前就進行列表的修改,以避免形成錯誤。
github 上有不少的 pub/sub 開源庫,若是沒有什麼特定的需求,找到代碼量最少的就是 mitt 這個庫了,做者是喜歡開發微型庫的 developit 大佬,著名的 preact 也是出於這位大佬之手。 這裏就不作過多的介紹,很是簡單。你們可能都能看明白,代碼以下(除去 flow 工具的檢查):
export default function mitt(all) { all = all || Object.create(null); return { on(type, handler) { (all[type] || (all[type] = [])).push(handler); }, off(type, handler) { if (all[type]) { all[type].splice(all[type].indexOf(handler) >>> 0, 1); } }, emit(type, evt) { (all[type] || []).slice().map((handler) => { handler(evt); }); (all['*'] || []).slice().map((handler) => { handler(type, evt); }); } }; }
僅僅只有3個方法,on emit以及 off。
只要在多個頁面導入 生成的 mitt() 函數生成的對象便可(或者直接放入 app.globalData 中也可)。
Component({ lifetimes: { attached: function() { // 頁面建立時執行 const changeData = (type, data) => { // 處理傳遞過來的類型與數據 } this._changed = changeData bus.on('xxxchanged', this._changed) }, detached: function() { // 頁面銷燬時執行 bus.off('xxxchanged', this._changed) } } })
這裏mitt能夠有多個頁面進行綁定事件,若是需求僅僅只涉及到兩個頁面之間,咱們就可使用 wx.navigateTo 中的 EventChannel (頁面間事件信息通道)。能夠參考微信小程序wx.navigateTo方法裏的events參數使用詳情及場景,該方案的利好在於,傳遞到下一個頁面的參數也能夠經過 EventChannel 來通知,以便於解決 properties 傳遞數據不宜過大的問題。
注: 一個頁面展現不少信息的時候,會形成小程序頁面的卡頓以及白屏。小程序官方也有長列表組件 recycle-view。有需求的狀況下能夠自行研究,這個不在這裏詳述。
若是你以爲這篇文章不錯,但願能夠給與我一些鼓勵,在個人 github 博客下幫忙 star 一下。
博客地址