這篇文章將為大家詳細(xì)講解有關(guān)如何解決Vue頁(yè)面固定滾動(dòng)位置的問(wèn)題,小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。
成都創(chuàng)新互聯(lián)專(zhuān)注于企業(yè)網(wǎng)絡(luò)營(yíng)銷(xiāo)推廣、網(wǎng)站重做改版、安達(dá)網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、H5頁(yè)面制作、商城開(kāi)發(fā)、集團(tuán)公司官網(wǎng)建設(shè)、成都外貿(mào)網(wǎng)站建設(shè)、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁(yè)設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性價(jià)比高,為安達(dá)等各大城市提供網(wǎng)站開(kāi)發(fā)制作服務(wù)。
問(wèn)題描述:
通常見(jiàn)于 列表頁(yè)List -> 詳情頁(yè)Detail 的情況, 從列表的某一項(xiàng)x 進(jìn)入到詳情頁(yè), 再返回的時(shí)候, 希望列表的位置固定在x, 而不是回到頂部了.
vue-router 里面是有一個(gè) scrollBehavior 的, 但是這個(gè)玩意只能在 history 模式下面使用, 而我用的 hash 模式.
所以我們要自己實(shí)現(xiàn)嘛, 思路簡(jiǎn)單:List 里面監(jiān)聽(tīng)滾動(dòng), 記錄滾動(dòng)位置 pos, 從 Detail 返回到 List 里面的時(shí)候, 讀取 pos.
mounted () { // 讀 setTimeut(function(){ document.body.scrollTop = parseInt(sessionStorage.getItem('pos')); }, 1000); // 存 window.onscroll = function () { sessionStorage.setItem('pos', document.body.scrollTop); } }
遇見(jiàn)了一個(gè)問(wèn)題:
每次返回 List, 都是直接滾動(dòng)到頂部, 每次都是, 每次都是! 把 pos 打印出來(lái), 發(fā)現(xiàn)是 0, 而不是我們所存的值. 日了, 明明切換之前還是的, 回來(lái)就不是了.
然后發(fā)現(xiàn)了路由每次切換都會(huì)觸發(fā) onscroll 事件, 日了狗, 為毛.我都沒(méi)有滾動(dòng)頁(yè)面, 為什么會(huì)觸發(fā) onscroll 事件。
剛開(kāi)始懷疑 hash 變化會(huì)導(dǎo)致 onscroll 事件的觸發(fā), 所以我就在瀏覽器里面手動(dòng)輸入了幾個(gè)不存在的路由:
/foo /bar
沒(méi)有發(fā)現(xiàn) scroll 被觸發(fā), 所以這個(gè)嫌疑排出.
然后懷疑 vue-router 里面是不是綁定了 scroll 事件, 沒(méi)發(fā)現(xiàn)然后又想, 沒(méi)綁定 scroll 事件, 那么修改 scrollTop 值會(huì)不會(huì)也觸發(fā) scroll 事件.
好吧還發(fā)現(xiàn)新知識(shí)點(diǎn)了:
scrollTop 值的改變, 的確會(huì)觸發(fā) scroll 事件.
那么我就想, 是不是 vue-router 里面存在修改 scrollTop 值的行為, 也沒(méi)有發(fā)現(xiàn).
然后我又想, 數(shù)據(jù)是動(dòng)態(tài)渲染的, 所以是不是和元素的增刪改查相關(guān)。
元素增加-> 頁(yè)面高度變了 -> 頁(yè)面高度變化, 也觸發(fā) scroll 事件?
所以我用 vue-cli 新建了項(xiàng)目, 放了兩個(gè)沒(méi)有增刪改查的路由
然后日了狗的, 我看見(jiàn)從 foo -> bar -> foo, 的時(shí)候, foo的滾動(dòng)條位置還在之前我滾動(dòng)到的地方.
突然想起來(lái)瀏覽器是可以自己記錄滾動(dòng)條位置的.
是不是瀏覽器干的?
從詳情頁(yè)返回到列表頁(yè)面, 列表會(huì)重新渲染, 時(shí)序大概是這樣:
返回列表頁(yè) 1
渲染頁(yè)面 2
而瀏覽器恢復(fù)滾動(dòng)條的位置的操作, 是在 1 和 2 之間, 這個(gè)時(shí)候就出問(wèn)題了:如果你頁(yè)面上面的數(shù)據(jù)都是渲染出來(lái)的, 瀏覽器就會(huì)發(fā)現(xiàn):
頁(yè)面的高度<=屏幕的高度, 不存在滾動(dòng)條, 此時(shí) document.body.scrollTop = 0;
所以會(huì)設(shè)置 document.body.scrollTop = 0
修改了 document.body.scrollTop 觸發(fā)了 scroll 事件, scroll 里面又重寫(xiě)了 pos
等你數(shù)據(jù)渲染結(jié)束之后, 讀到的就是 0了.
如果發(fā)現(xiàn)你頁(yè)面高度大于屏幕高度, 但是頁(yè)面高度是 n, 而 pos 的值是: n + x, 比當(dāng)前頁(yè)面的最大的 scrollTop 值還大, 這個(gè)時(shí)候, document.body.scrollTop 的值就會(huì)等于 n.
當(dāng)你的數(shù)據(jù)渲染結(jié)束, 開(kāi)始定位, 日了, 沒(méi)定準(zhǔn).
所以我們要解決這個(gè)問(wèn)題.
當(dāng)然是想到了 keep-alive, 剛啟用的時(shí)候, 發(fā)現(xiàn)的確不錯(cuò). 但是同時(shí)也發(fā)現(xiàn):
列表項(xiàng)目靠前的, 往返操作的定位都很準(zhǔn), 越往后越不行, 直接拉到底, 再返回發(fā)現(xiàn)定位到的一般都是第二個(gè)第三個(gè)列表項(xiàng)目.
所以這個(gè)就很有意思了, 我大概猜測(cè)了一下瀏覽器的滾動(dòng)位置恢復(fù)行為:
當(dāng) hashchange 的時(shí)候。拿到當(dāng)前頁(yè)面的 document.body.scrollTop 值, 和自己存儲(chǔ)的滾動(dòng)條位置。二者取最小的值, 設(shè)置成當(dāng)前的 document.body.scrollTop 的值, 當(dāng)使用 keep-alive 的時(shí)候, 因?yàn)?hashchange 事件處理和頁(yè)面渲染是并行的, 所以有時(shí)hashchange 拿到的 document 的高度是已經(jīng)渲染過(guò)幾個(gè)元素的高度, 這個(gè)就是為什么定不準(zhǔn)的原因.
好吧, 現(xiàn)在的情況是:
keep-alive 定不準(zhǔn), 不可靠, 所以需要我們自己來(lái)重新定位.
ok, 1 先綁定 scroll 事件:
var map = {}; window.onscroll = function() { map[location.hash] = document.body.scrollTop; }
2 再屏蔽掉瀏覽器自動(dòng)恢復(fù)滾動(dòng)位置行為帶來(lái)的影響
a 在 hashchange 時(shí)強(qiáng)制 document.body.scrollTop = 0
b 在 scroll 事件里面, 當(dāng) document.body.scrollTop = 0 的時(shí)候不做 存操作.
var map = {}; window.onhashchange = function() { document.body.scrollTop = 0; } window.onscroll = function() { if (document.body.scrollTop) { // 存 map[location.hash] = document.body.scrollTop; } else { // 讀 } }
3 在讀操作里面, 設(shè)置一個(gè)定時(shí)任務(wù), 去判斷 document.body.scrollTop 的值和你保存的位置是不是相同的
var map = {}; window.onhashchange = function() { document.body.scrollTop = 0; } window.onscroll = function() { if (document.body.scrollTop) { // 存 map[location.hash] = document.body.scrollTop; } else { var timer = null; timer = setInterval(function(){ if (document.body.scrollTop == map[location.hash]) { clearInterval(timer); } else { document.body.scrollTop = map[location.hash]; } }, 20); } }
到這里實(shí)際上已經(jīng)大體實(shí)現(xiàn)了, 返回恢復(fù)滾動(dòng)條位置的功能, 而上面的代碼需要更多的優(yōu)化,
關(guān)于“如何解決Vue頁(yè)面固定滾動(dòng)位置的問(wèn)題”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。