Laravel+Vue.js开发MPA应用返回页面强制刷新丢失滚动位置如何解决
问题根因
纯Blade开发时浏览器会默认启用往返缓存(bfcache),返回时可以直接恢复之前的页面状态和滚动位置。但加入Vue后,页面加载时会重新初始化Vue实例、重绘#app节点内的全部DOM,破坏了bfcache的恢复逻辑,导致浏览器默认滚动恢复失效。
解决方案
方案1:轻量手动缓存(改动最小,适配无限滚动场景)
该方案不需要调整现有架构,仅需在商品列表页补充存储逻辑即可:
- 开启手动滚动恢复控制,避免浏览器默认滚动和自定义逻辑冲突,在
resources/js/app.js的Vue实例初始化前加入以下代码:if ('scrollRestoration' in window.history) { window.history.scrollRestoration = 'manual' } - 在商品列表页的Vue逻辑中补充状态存储和恢复逻辑:
- 页面离开前(监听
beforeunload事件),把当前滚动高度、已加载的商品列表数据、当前分页页码存在sessionStorage中 - 页面
mounted钩子触发时,先判断sessionStorage里是否有对应缓存数据:- 存在缓存的话直接把数据赋值给列表渲染变量,跳过首次接口请求
- 等DOM渲染完成(通过
$nextTick监听)后,把页面滚动到缓存的高度
- 主动刷新页面或者从其他非详情页进入列表页时,清空
sessionStorage里的对应缓存即可
- 页面离开前(监听
- 参考代码:
// 商品列表页的Vue逻辑 export default { data() { return { goodsList: [], page: 1 } }, mounted() { // 判断是否为从商品详情页返回的场景 const listCache = sessionStorage.getItem('goodsListCache') if (listCache && document.referrer.includes('/product/')) { const { list, page, scrollTop } = JSON.parse(listCache) this.goodsList = list this.page = page this.$nextTick(() => { window.scrollTo(0, scrollTop) }) } else { // 正常首次加载请求列表 this.loadGoodsList() sessionStorage.removeItem('goodsListCache') } // 绑定事件监听 window.addEventListener('scroll', this.saveScrollTop) window.addEventListener('beforeunload', this.saveListCache) }, beforeDestroy() { // 解绑事件避免内存泄漏 window.removeEventListener('scroll', this.saveScrollTop) window.removeEventListener('beforeunload', this.saveListCache) }, methods: { saveScrollTop() { const cache = JSON.parse(sessionStorage.getItem('goodsListCache') || '{}') cache.scrollTop = window.pageYOffset || document.documentElement.scrollTop sessionStorage.setItem('goodsListCache', JSON.stringify(cache)) }, saveListCache() { const cache = { list: this.goodsList, page: this.page, scrollTop: window.pageYOffset || document.documentElement.scrollTop } sessionStorage.setItem('goodsListCache', JSON.stringify(cache)) }, loadGoodsList() { // 原有请求商品列表接口的逻辑 } } }
方案2:适配bfcache(性能更优)
如果不想手动存储业务状态,可以调整Vue初始化逻辑适配浏览器往返缓存:
- 不要直接挂载Vue到
<body>下的根节点,调整为DOM完全加载后再挂载Vue - 避免在Vue初始化阶段修改根节点的布局属性,减少bfcache失效的触发条件
- 可通过
pageshow事件判断页面是否从缓存恢复,直接恢复滚动位置:window.addEventListener('pageshow', (e) => { if (e.persisted) { // 标识页面从bfcache恢复,未重新加载 const scrollTop = sessionStorage.getItem('listScrollTop') if (scrollTop) window.scrollTo(0, scrollTop) } })
注意事项
sessionStorage仅在当前标签页生效,关闭标签后自动清除,不会残留冗余数据,完全适配该场景需求。如果需要跨标签页存储可以替换为localStorage,注意要在合适的时机清空避免脏数据。
内容的提问来源于stack exchange,提问作者Christopher Lin
相关产品推荐
相关产品推荐

