導語:本文主要介紹在小程序中,多頁面之間如何保持數據同步javascript
在不少的產品中,都會存在跨頁面間須要數據同步,以下示例:前端
爲了更好的理解該場景,咱們再詳細描繪一下:java
動態廣場
、我的中心
、個人動態
、動態詳情
動態廣場
頁,請求加載數據,展現動態列表,其中,咱們用綠色內陰影區分該條動態是「個人」,其餘未加內陰影的表示是「別人的」;我的中心
頁,請求加載數據,展現獲贊數量;個人動態
頁,請求加載數據,展現個人動態列表;動態詳情
頁,請求加載數據,進行點贊
操做;個人動態
頁,能夠看到該條動態點贊狀態和數量發生變化,已經同步;我的中心
頁,也能夠看到獲贊數量發生變化,已經同步;動態廣場
頁,也能夠看到對應的一條動態點贊狀態和數量發生變化,已經同步;下面咱們來探討一下這個場景的實現,在此以前,咱們先要了解在點贊時,該場景中各頁面的狀態及關係。git
如上圖所示,當咱們在點贊時,4個頁面都已經在是打開的(4個webview
)。當咱們點同意功時,點擊左上解返回時,動態詳情
頁的webview
關掉,直接看到下一層webview
,也就是個人動態
頁,這個頁面是已經存在的。其餘頁面也是如此。web
那對於這些已經存在的頁面,咱們應該如何同步更新數據呢?小程序
固然,若是比較懶,能夠直接在onShow
的時候從新拉數據渲染頁面。但顯然這是很是低級、不可取也不必的作法。從新拉數據須要耗時,頁面從新渲染也會看到閃屏,關鍵是根本不必從新拉數據,由於數據發生了變化,前端是知道的。框架
因此咱們能夠這樣作,在動態詳情頁點同意功時,保存一個數據到全局globalData
中去,回到個人動態頁,在onShow
中去檢測全局globalData
中是否有點贊變化的數據,有的話,就讀取出來去更新相應的動態。ui
// 動態詳情頁js
onLike() {
...
success: () => {
App.globalData.like = {
fid: 10001,
likes: 1,
hasLike: true
}
}
}
// 個人動態頁js
onShow() {
if(App.globalData.like !== null) {
// 讀取globaldata.like數據去更新
this.doUpdata()
// 特別須要注意,更新完後,須要把globaldata.like清掉,否則下次onShow還會繼續走到該邏輯
App.globalData.like = null
}
}
複製代碼
這樣彷佛能夠達到咱們的目的,無請求、純前端局部更新。this
但這樣還存在一個問題,當咱們再退回到我的中心
頁時,要檢查下獲贊數量是否須要更新,以及回到動態廣場
頁時,也要檢查點贊有沒有發生變化。但在這兩個頁面onShow
去判斷App.globalData.like
時,都已經檢測不到了,由於該數據已經在個人動態
頁onShow
中置爲null
了。spa
歸納來講,在點贊時,只生產了一條數據,但有多個消費者,哪一個頁面先把數據消費了,其餘頁面也就沒法檢測到數據了。
由此,咱們想到那就使用EventBus
來處理。
首先,咱們本身實現一套簡單的EventBus。
在小程序啓動時,初始化EventBus:
const Event = require('/util/events.js').default
App({
events: null,
onLaunch(options) {
this.initEvents()
// doOtherThings
},
initEvents() {
this.events = new Event()
},
emitFeedsLike(data) {
this.events.emit('feedsLike', data)
},
emitPublishFeeds(data) {
this.events.emit('publishFeeds', data)
},
...
}
複製代碼
各個頁面在onLoad時,註冊監聽事件(在此以個人動態頁爲例):
// 個人動態.js
const App = getApp()
Page({
data: {
list: []
},
onLoad: function (options) {
...
// 監聽點贊事件廣播
↓ 重點在這裏 ↓
App.events.on('feedsLike', data => {
console.log('個人動態頁面收到點贊變化通知:', data)
// 進行更新操做
})
// 監聽發佈事件廣播
↓ 重點在這裏 ↓
App.events.on('publishFeeds', data => {
console.log('個人動態頁面收到發佈動態通知:', data)
// 進行更新操做
})
},
...
})
複製代碼
而後在動態點贊時,發出事件通知。(這裏一條動態是封裝成組件,不屬於某一個頁面,點贊事件也是封裝在組件內)
const App = getApp()
Component({
properties: {...},
methods: {
// 點贊
tapLike(e) {
let { likes, hasLike } = this.data
likes += (hasLike && -1 || 1)
hasLike = !hasLike
this.updateFeeds(likes, hasLike).then(() => {
this.setData({
likes,
hasLike
})
// 廣播事件
↓ 重點在這裏 ↓
App.emitFeedsLike({
uid: this.data.uid,
fid: this.data.fid,
likes,
hasLike
})
})
},
...
}
})
複製代碼
這樣,咱們便在小程序中實現了一套跨頁面數據同步的方案。
直觀上這已經很是完美的實現了咱們的需求。但在小程序中存在一個與咱們常規經驗不太一致的地方。那就是頁面在關掉後,它裏面的對象並無銷燬,這點是由於小程序的邏輯層是共用一個進程。
所以,每次進入頁面,都會註冊一次監聽事件,而退出頁面後,該事件並不會銷燬。這樣的話,屢次重複進入頁面,就會註冊多個重複事件,當事件發生時,就會執行屢次響應。請仔細觀察下圖!
爲了不該現象出現,咱們切記要在頁面的onUnload事件中,主動銷燬監聽事件。
Page({
eventsListener: {},
data: {
list: []
},
onLoad: function (options) {
...
// 監聽點贊事件廣播
↓ 重點在這裏 ↓
this.eventsListener.feedsLike = App.events.on('feedsLike', data => {
console.log('個人動態頁面收到點贊變化通知:', data)
// 進行更新操做
})
// 監聽發佈事件廣播
↓ 重點在這裏 ↓
this.eventsListener.publishFeeds= App.events.on('publishFeeds', data => {
console.log('個人動態頁面收到發佈動態通知:', data)
// 進行更新操做
})
},
↓ 重點在這裏 ↓
onUnload() {
for (let i in this.eventsListener) {
App.events.remove(i, this.eventsListener[i])
}
},
...
})
複製代碼
至此,咱們在小程序中完美的實現了跨頁面/組件、多頁面數據同步。
本文研究的demo都可以小程序中體驗,項目源碼:git.weixin.qq.com/xinyuanliu/…
歡迎交流討論。
下面是廣告時間
尚未看夠?知名小程序跨端框架 Taro 的做者,面對面教你使用 React Hooks 來重構你的小程序,讓你更加優雅地進行小程序的數據管理,更有小程序雲開發,企業級小程序開發實踐等硬核內容,要你好看!掃描下方二維碼查看具體詳情。