前文的解決方法 其實是有問題的。
1. 問題
前文提到 saved_position 的返回值有時是 undefined,有時是 null。經(jīng)過仔細調(diào)試,可以發(fā)現(xiàn) undefined 只會出現(xiàn)一次,以后都是出現(xiàn) null。出現(xiàn)的過程為:
- 用戶訪問具有 keep-alive 的 List 頁面
- 用戶點擊 router-link 切換到其他頁面
- 點擊瀏覽器后退按鈕,回到 List 頁面,此時的 saved_position 值即為 undefined
- 之后所有的后退前進都是 null,不再有 undefined。
但是步驟 3 當中,其實應該是有值的,但 vue 的實現(xiàn)中會生成很多的 _key,這個實現(xiàn)其實是有問題的,生成了很多多余的 _key,導致與用戶的瀏覽器歷史行為不一致,導致出現(xiàn) undefined。
2.終極解決文案
既然 vue-router 保存的滾動條值是錯誤的,那么我們自己保存好了,然后在適當?shù)臅r機進行“位置修復”。
# router.coffee
router = new VueRouter(
mode: 'history'
routes: [
{
path: '/list'
name: 'list'
meta:
title: '列表頁'
keep_alive: true
saved_position: {x: 0, y: 0} # 這里新增設(shè)置默認值為頂頂
component: require('../views/list.vue')
},
...
]
scrollBehavior: (to, from, saved_position) ->
# 點擊了非瀏覽器按鈕,則設(shè)置為 null,方便組件中刷新 ajax 數(shù)據(jù)
if saved_position == null
if to.meta.keep_alive
to.meta.saved_position = null
# 點擊了瀏覽器前進/后退,則直接使用正確的位置,并且組件知道不是 null,
# 不會刷新 ajax 數(shù)據(jù)
else
saved_position = to.meta.saved_position
return saved_position ? {x: 0, y: 0}
)
router.beforeEach (to, from, next) ->
# 存儲滾動條位置
if from.meta.keep_alive
from.meta.saved_position =
x: window.pageXOffset
y: window.pageYOffset
next()
我們在,router.beforeEach 中在頁面切換之前,保存當前滾動條的位置到相關(guān)的 meta.saved_position 中。
在 scrollBehavior 中還原,這樣位置就不會出現(xiàn) undefined 了。
接下來就是在組件中如何更新 ajax 數(shù)據(jù)了:
# list.coffee
export default Dashboard =
name: 'Dashboard'
data: ->
posts: []
beforeRouteEnter: (to, from, next) ->
next (vm) ->
# 如果為 null,則說明點擊了 router-link,此時可刷新 ajax 數(shù)據(jù)。
# 否則,為點擊了瀏覽器后退/前進,什么也不做即可。
# 交給 keep-alive 處理緩存,scrollBehavior 處理修復后的滾動條位置。
if to.meta.saved_position == null
vm.fetchPosts()
# 或者你有其他控制邏輯,如:
# 帖子列表為空時,也強制獲取 ajax 數(shù)據(jù):
if (to.meta.saved_position == null) or (vm.posts.length == 0)
vm.fetchPosts()
methods:
fetchPosts: (type) ->
@$store
.dispatch(types.dashboard.actions.GET_POSTS)
.then (res) =>
...
以上。