1. keep-alive
-
問題: 使用keep-alive標籤後部分安卓機返回快取頁位置不精確問題
-
解決方案:
<div id="app">
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>
</div>
複製程式碼
const router = new Router({
scrollBehavior(to, from, savedPosition) {
if (savedPosition && to.meta.keepAlive) {
return savedPosition;
}
return { x: 0, y:0 };
},
});
複製程式碼
2. 頁面返回出現空白屏問題
- 問題
【前提】:iOS裝置
【步驟】: 頁面A是個列表很長-->滑到頁尾的時候點選跳轉之後到頁面B--->再返回A頁面
--->螢幕會出現空白遮罩層--->手指輕觸螢幕滑動--->遮罩層消失
複製程式碼
解決方案一
在介面請求成功後的回撥操作完成後進行該操作,例如
// fetchCourseList是一個封裝好的Promise請求
fetchCourseList().then(({ data: courses }) => {
this.courses = courses;
}).then(() => {
setTimeout(() => {
window.scrollTo(0, 1);
window.scrollTo(0, 0);
});
});
複製程式碼
該方案的弊端: 每個頁面都需要做這樣的處理,不推薦使用。
解決方案二(推薦)
使用scrollBehavior中的非同步滾動操作
const router = new Router({
scrollBehavior(to, from, savedPosition) {
// keep-alive 返回快取頁面後記錄瀏覽位置
if (savedPosition && to.meta.keepAlive) {
return savedPosition;
}
// 非同步滾動操作
return new Promise((resolve) => {
setTimeout(() => {
resolve({ x: 0, y: 1 });
}, 0);
});
},
});
複製程式碼
該方案直接在路由進行處理,相容每個頁面並且頁面載入完後並也不會產生1px的滾動位置。
這裡為什麼不能直接return而必須使用非同步滾動操作呢?以下是個人的一些見解歡迎大家來探討指正。
-
首先我們要先去了解scrollBehavior函式究竟在元件的哪個生命週期後才開始執行。這裡我對元件的每個生命週期和scrollBehavior函式進行alert,經排查結果:scrollBehavior函式在元件的生命週期mounted後beforeUpdate前執行。
-
在scrollBehavior函式中直接return{ x:0, y:100},進入頁面仍在頂部。為什麼不會滾動到100px處?猜測:mounted中的非同步請求回來的資料賦值給data中的變數a,變數a因為vue的雙向繫結更新了view層而引起滾動失效?
-
驗證下以上的猜測,設定一個靜態頁面資料都已經在html上寫死。scrollBehavior函式中直接return { x:0, y: 100},結果:進入頁面都會滾動到100px處。證明:確實與非同步請求回來後的操作有關係。
-
接著瞭解vue的mounted和beforeUpdate時期都做了些什麼。mounted時期:data資料已經掛在到頁面上。beforeUpdate和updated時期:當vue發現data中的資料發生了改變,會觸發對應元件的重新渲染。
-
根據步驟4.mounted時期發起的非同步請求並不會阻礙主執行緒的後續操作,所以請求回撥事件未觸發(對data中的變數a賦值操作未執行)便繼續去執行scrollBehavior函式。如果此時直接return{ x:0, y:100}。此時相當於在非同步請求回撥事件未執行前進行了滾動。等到滾動後非同步請求回撥事件開始執行,對data中的變數a被賦值,引起元件重新渲染又回到了頂部。這整個流程滾動是針對data的初始資料頁進行滾動的,所以遮罩層仍會出現。
-
綜合上述:必須使用非同步滾動,利用setTimeout跳出主執行緒將回撥事件放到佇列中。由於mouted比scrollBehavior函式早執行,所以非同步請求的回撥事件優先進入佇列,接下去才是setTimeout的回撥事件。根據佇列 先進先出的原理。先執行了非同步請求回撥事件對data中的變數a做賦值操作。此時相當於這已經是個靜態頁面了,接著我只要執行return { x:0, y: 100 }。這樣就已經觸發了頁面滾動到100px的效果。但是由於data資料發生改變,頁面重新渲染又回到頂部。這時整個輕觸滾動效果已經暗中執行完成,不會再出現遮罩層了。