問題
先總結一下無法刷新頁面或組件視圖數據的可能原因:
- 數據本身的問題
- 沒有爲模塊或組件創建
key
- 路由使用不當
以我個人的經歷,目前歸結爲此三點,本文主要探討後兩個問題的解決辦法,當然可能還有其他問題, 歡迎各位同行與我交流。
場景
最近做一個教育類APP的二次開發,使用的是Uni-app,做的差不多的時候出現一個問題:登錄後,用戶中心主頁頁面的視圖數據無論怎樣都無法刷新,然後試了各種方法,最後發現問題的關鍵之前的開發對登錄後的跳轉做了錯誤的處理,即使用了 uni.navigateTo
,而驗證登錄狀態後,在沒有登錄的情況下跳轉到登錄頁同樣也是使用了 uni.navigateTo
。
其實 uni.navigateTo
在登錄後的內頁使用是非常合適的,因爲它會緩存頁面和數據,所以能很好的提高APP性能和用戶體驗。
但如果在登錄之初就使用 uni.navigateTo
,這就很致命,因爲登錄成功之前一般還無法獲取APP的內頁數據的,如果使用了 uni.navigateTo
,就會導致登錄成功後, 即便已經刷新了數據,併成功加入了緩存,你會發現通過 uni.navigateTo
加載的主頁的視圖數據還是不會刷新,因爲 uni.navigateTo
把頁面緩存了,這種用法實在太坑了。
有人可能會說,我在頁面、組件生命週期裏面更新數據不就完了嗎?其實大部分方法是不可行的,因爲頁面緩存後再返回,在不刷新頁面的情況下,生命週期中的方法不會被調用,當然 setTimeout()
或者 setInterval()
除外(但這這種辦法會損失性能,如果處理不當用戶體驗會很糟)
解決辦法
1. 數據本身的問題
如網絡問題,或者處理的方式和時機(生命週期)不當,這個需要自查,不在本文討論範圍內。
2. 沒有爲模塊或組件創建 key
目前 uni-app
還無法使用類似 Vue
中的 watch
方法來監聽數據變化以更新視圖,也無法監聽 data
中數組或對象的變化。
所以碰到需要動態更新數據,刷新頁面或組件視圖時,需要使用 key
屬性來刷新,代碼示例如下:
數據處理完成後,通過修改 key
的值變可以刷新該模塊或組件,前提是爲該模塊或組件設置了 key
屬性
<template>
<view>
<view class="module-box1" :key="moduleKey"></view>
<commponent1 v-if="PageCur=='commponent1'" :key="commponent1Key"></commponent1>
<commponent2 v-if="PageCur=='commponent2'" :key="commponent2Key"></commponent2>
<view class="module-box2">
<button @tap="tapMenu" :data-cur="commponent1">按鈕1</button>
<button @tap="tapMenu" :data-cur="commponent2">按鈕1</button>
</view>
</view>
</template>
<script>
export default {
data() {
return {
PageCur: 'commponent1',
moduleKey: 0,
commponent1Key: 0,
commponent2Key: 0,
},
};
},
onLoad() {
//獲取數據
this.getData()
},
methods: {
getData() {
var that = this
//獲取數據
uni.request({
url: 'https://www.example.com/request',
success: (res) => {
console.log(res.data);
//相關處理
//最後更新相應模塊或組件的key
++that.moduleKey
++that.commponent1Key
++that.commponent2Key
}
});
},
tapMenu(e) {
var that = this
this.PageCur = e.currentTarget.dataset.cur
},
}
</script>
3. 路由使用不當
比如我現在碰到的問題,在登錄的地方錯誤使用了 uni.navigateTo(OBJECT)
,解決辦法就是改爲 uni.redirectTo(OBJECT)
或者 uni.reLaunch(OBJECT)
,這兩個方法都會關閉當前頁面再跳轉,區別是後者會把所有頁面都關閉。
在登錄處理中建議使用 uni.reLaunch(OBJECT)
uni.reLaunch({
url: '../dirName/moduleName'
});