問題: 使用keep-alive標籤後部分安卓機返回緩存頁位置不精確問題html
解決方案:vue
<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 };
},
});
複製代碼
【前提】:iOS設備
【步驟】: 頁面A是個列表很長-->滑到頁腳的時候點擊跳轉以後到頁面B--->再返回A頁面
--->屏幕會出現空白遮罩層--->手指輕觸屏幕滑動--->遮罩層消失
複製代碼
在接口請求成功後的回調操做完成後進行該操做,例如緩存
// fetchCourseList是一個封裝好的Promise請求
fetchCourseList().then(({ data: courses }) => {
this.courses = courses;
}).then(() => {
setTimeout(() => {
window.scrollTo(0, 1);
window.scrollTo(0, 0);
});
});
複製代碼
該方案的弊端: 每一個頁面都須要作這樣的處理,不推薦使用。bash
使用scrollBehavior中的異步滾動操做app
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的滾動位置。異步
首先咱們要先去了解scrollBehavior函數究竟在組件的哪一個生命週期後纔開始執行。這裏我對組件的每一個生命週期和scrollBehavior函數進行alert,經排查結果:scrollBehavior函數在組件的生命週期mounted後beforeUpdate前執行。函數
在scrollBehavior函數中直接return{ x:0, y:100},進入頁面仍在頂部。爲何不會滾動到100px處?猜想:mounted中的異步請求回來的數據賦值給data中的變量a,變量a由於vue的雙向綁定更新了view層而引發滾動失效?fetch
驗證下以上的猜想,設置一個靜態頁面數據都已經在html上寫死。scrollBehavior函數中直接return { x:0, y: 100},結果:進入頁面都會滾動到100px處。證實:確實與異步請求回來後的操做有關係。ui
接着瞭解vue的mounted和beforeUpdate時期都作了些什麼。mounted時期:data數據已經掛在到頁面上。beforeUpdate和updated時期:當vue發現data中的數據發生了改變,會觸發對應組件的從新渲染。this
根據步驟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數據發生改變,頁面從新渲染又回到頂部。這時整個輕觸滾動效果已經暗中執行完成,不會再出現遮罩層了。