詳解小程序開發(fā)經(jīng)驗:多頁面數(shù)據(jù)同步
導(dǎo)語:本文主要介紹在小程序中,多頁面之間如何保持?jǐn)?shù)據(jù)同步
在很多的產(chǎn)品中,都會存在跨頁面間需要數(shù)據(jù)同步,如下示例:

為了更好的理解該場景,我們再詳細(xì)描繪一下:
- 本場景包括4個頁面:動態(tài)廣場、個人中心、我的動態(tài)、動態(tài)詳情
- 首先,進(jìn)入動態(tài)廣場頁,請求加載數(shù)據(jù),展示動態(tài)列表,其中,我們用綠色內(nèi)陰影區(qū)分該條動態(tài)是“我的”,其他未加內(nèi)陰影的表示是“別人的”;
- 然后,進(jìn)入個人中心頁,請求加載數(shù)據(jù),展示獲贊數(shù)量;
- 點(diǎn)擊我的動態(tài),進(jìn)入我的動態(tài)頁,請求加載數(shù)據(jù),展示我的動態(tài)列表;
- 點(diǎn)擊其中一條動態(tài),進(jìn)入動態(tài)詳情頁,請求加載數(shù)據(jù),進(jìn)行點(diǎn)贊操作;
- 在第5步中,點(diǎn)贊成功后,回退到我的動態(tài)頁,可以看到該條動態(tài)點(diǎn)贊狀態(tài)和數(shù)量發(fā)生變化,已經(jīng)同步;
- 再回到到個人中心頁,也可以看到獲贊數(shù)量發(fā)生變化,已經(jīng)同步;
- 再回到動態(tài)廣場頁,也可以看到對應(yīng)的一條動態(tài)點(diǎn)贊狀態(tài)和數(shù)量發(fā)生變化,已經(jīng)同步;
下面我們來探討一下這個場景的實現(xiàn),在此之前,我們先要了解在點(diǎn)贊時,該場景中各頁面的狀態(tài)及關(guān)系。


如上圖所示,當(dāng)我們在點(diǎn)贊時,4個頁面都已經(jīng)在是打開的(4個webview)。當(dāng)我們點(diǎn)贊成功時,點(diǎn)擊左上解返回時,動態(tài)詳情頁的webview關(guān)掉,直接看到下一層webview,也就是我的動態(tài)頁,這個頁面是已經(jīng)存在的。其他頁面也是如此。
那對于這些已經(jīng)存在的頁面,我們應(yīng)該如何同步更新數(shù)據(jù)呢?
當(dāng)然,如果比較懶,可以直接在onShow的時候重新拉數(shù)據(jù)渲染頁面。但顯然這是非常低級、不可取也沒必要的做法。重新拉數(shù)據(jù)需要耗時,頁面重新渲染也會看到閃屏,關(guān)鍵是根本沒必要重新拉數(shù)據(jù),因為數(shù)據(jù)發(fā)生了變化,前端是知道的。
所以我們可以這樣做,在動態(tài)詳情頁點(diǎn)贊成功時,保存一個數(shù)據(jù)到全局globalData中去,回到我的動態(tài)頁,在onShow中去檢測全局globalData中是否有點(diǎn)贊變化的數(shù)據(jù),有的話,就讀取出來去更新相應(yīng)的動態(tài)。
// 動態(tài)詳情頁js
onLike() {
...
success: () => {
App.globalData.like = {
fid: 10001,
likes: 1,
hasLike: true
}
}
}
// 我的動態(tài)頁js
onShow() {
if(App.globalData.like !== null) {
// 讀取globaldata.like數(shù)據(jù)去更新
this.doUpdata()
// 特別需要注意,更新完后,需要把globaldata.like清掉,不然下次onShow還會繼續(xù)走到該邏輯
App.globalData.like = null
}
}
這樣似乎可以達(dá)到我們的目的,無請求、純前端局部更新。
但這樣還存在一個問題,當(dāng)我們再退回到個人中心頁時,要檢查下獲贊數(shù)量是否需要更新,以及回到動態(tài)廣場頁時,也要檢查點(diǎn)贊有沒有發(fā)生變化。但在這兩個頁面onShow去判斷App.globalData.like時,都已經(jīng)檢測不到了,因為該數(shù)據(jù)已經(jīng)在我的動態(tài)頁onShow中置為null了。
概括來說,在點(diǎn)贊時,只生產(chǎn)了一條數(shù)據(jù),但有多個消費(fèi)者,哪個頁面先把數(shù)據(jù)消費(fèi)了,其他頁面也就無法檢測到數(shù)據(jù)了。
由此,我們想到那就使用EventBus來處理。
首先,我們自己實現(xiàn)一套簡單的EventBus。
源碼見:git.weixin.qq.com/xinyuanliu/…
在小程序啟動時,初始化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時,注冊監(jiān)聽事件(在此以我的動態(tài)頁為例):
// 我的動態(tài).js
const App = getApp()
Page({
data: {
list: []
},
onLoad: function (options) {
...
// 監(jiān)聽點(diǎn)贊事件廣播
↓ 重點(diǎn)在這里 ↓
App.events.on('feedsLike', data => {
console.log('我的動態(tài)頁面收到點(diǎn)贊變化通知:', data)
// 進(jìn)行更新操作
})
// 監(jiān)聽發(fā)布事件廣播
↓ 重點(diǎn)在這里 ↓
App.events.on('publishFeeds', data => {
console.log('我的動態(tài)頁面收到發(fā)布動態(tài)通知:', data)
// 進(jìn)行更新操作
})
},
...
})
然后在動態(tài)點(diǎn)贊時,發(fā)出事件通知。(這里一條動態(tài)是封裝成組件,不屬于某一個頁面,點(diǎn)贊事件也是封裝在組件內(nèi))
const App = getApp()
Component({
properties: {...},
methods: {
// 點(diǎn)贊
tapLike(e) {
let { likes, hasLike } = this.data
likes += (hasLike && -1 || 1)
hasLike = !hasLike
this.updateFeeds(likes, hasLike).then(() => {
this.setData({
likes,
hasLike
})
// 廣播事件
↓ 重點(diǎn)在這里 ↓
App.emitFeedsLike({
uid: this.data.uid,
fid: this.data.fid,
likes,
hasLike
})
})
},
...
}
})
這樣,我們便在小程序中實現(xiàn)了一套跨頁面數(shù)據(jù)同步的方案。
直觀上這已經(jīng)非常完美的實現(xiàn)了我們的需求。但在小程序中存在一個與我們常規(guī)經(jīng)驗不太一致的地方。那就是頁面在關(guān)掉后,它里面的對象并沒有銷毀,這點(diǎn)是因為小程序的邏輯層是共用一個進(jìn)程。

因此,每次進(jìn)入頁面,都會注冊一次監(jiān)聽事件,而退出頁面后,該事件并不會銷毀。這樣的話,多次重復(fù)進(jìn)入頁面,就會注冊多個重復(fù)事件,當(dāng)事件發(fā)生時,就會執(zhí)行多次響應(yīng)。請仔細(xì)觀察下圖!

為了避免該現(xiàn)象出現(xiàn),我們切記要在頁面的onUnload事件中,主動銷毀監(jiān)聽事件。
Page({
eventsListener: {},
data: {
list: []
},
onLoad: function (options) {
...
// 監(jiān)聽點(diǎn)贊事件廣播
↓ 重點(diǎn)在這里 ↓
this.eventsListener.feedsLike = App.events.on('feedsLike', data => {
console.log('我的動態(tài)頁面收到點(diǎn)贊變化通知:', data)
// 進(jìn)行更新操作
})
// 監(jiān)聽發(fā)布事件廣播
↓ 重點(diǎn)在這里 ↓
this.eventsListener.publishFeeds= App.events.on('publishFeeds', data => {
console.log('我的動態(tài)頁面收到發(fā)布動態(tài)通知:', data)
// 進(jìn)行更新操作
})
},
↓ 重點(diǎn)在這里 ↓
onUnload() {
for (let i in this.eventsListener) {
App.events.remove(i, this.eventsListener[i])
}
},
...
})
至此,我們在小程序中完美的實現(xiàn)了跨頁面/組件、多頁面數(shù)據(jù)同步。
本文研究的demo均可以小程序中體驗,項目源碼:git.weixin.qq.com/xinyuanliu/…
以上所述是小編給大家介紹的小程序開發(fā)經(jīng)驗:多頁面數(shù)據(jù)同步詳解整合,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關(guān)文章
探索JavaScript函數(shù)的無限可能(函數(shù)基本概念)
JavaScript中的函數(shù)是一種重要的編程概念,它允許我們封裝可重用的代碼塊,并在需要時進(jìn)行調(diào)用,本文將深入介紹JavaScript函數(shù)的各個方面,包括函數(shù)定義和調(diào)用、參數(shù)和返回值、作用域和閉包、高階函數(shù)以及常見的函數(shù)應(yīng)用場景,感興趣的朋友一起看看吧2023-08-08
javascript之典型高階函數(shù)應(yīng)用介紹
這幾個方法均為javascript 1.6 數(shù)組新增的方法。是很典型的functional 函數(shù),當(dāng)然也非常實用。下面是functional的定義并不來自javascript2013-01-01
javascript Array對象基礎(chǔ)知識小結(jié)
感覺自己對Array對象總是有種朦朧的感覺,今天自己手寫總結(jié),加深一下印象。2010-11-11
關(guān)于JavaScript中高階函數(shù)的魅力詳解
高階函數(shù):英文叫Higher-order function。JavaScript的函數(shù)其實都指向某個變量。下面這篇文章主要給大家介紹了關(guān)于JavaScript中高階函數(shù)的魅力,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2018-09-09
Javascript Function對象擴(kuò)展之延時執(zhí)行函數(shù)
這篇文章主要介紹 在js里面怎么延時執(zhí)行一個函數(shù)?2010-07-07
js字符串轉(zhuǎn)換成數(shù)字與數(shù)字轉(zhuǎn)換成字符串的實現(xiàn)方法
本篇文章主要是對js字符串轉(zhuǎn)換成數(shù)字與數(shù)字轉(zhuǎn)換成字符串的實現(xiàn)方法進(jìn)行了詳細(xì)的介紹,需要的朋友可以過來參考下,希望對大家有所幫助2014-01-01

