解决Vue页面固定滚动位置的处理办法

发布时间 - 2026-01-11 02:19:17    点击率:

最近做项目遇到一个问题,就是Vue滚动不固定,网上找了一些资料,说下 vue 固定滚动位置的处理办法.

问题描述:

通常见于 列表页List -> 详情页Detail 的情况, 从列表的某一项x 进入到详情页, 再返回的时候, 希望列表的位置固定在x, 而不是回到顶部了.

vue-router 里面是有一个 scrollBehavior 的, 但是这个玩意只能在 history 模式下面使用, 而我用的 hash 模式.

所以我们要自己实现嘛, 思路简单:List 里面监听滚动, 记录滚动位置 pos, 从 Detail 返回到 List 里面的时候, 读取 pos.

 mounted () {
  // 读
  setTimeut(function(){
   document.body.scrollTop = parseInt(sessionStorage.getItem('pos'));
  }, 1000);
  // 存
  window.onscroll = function () {
   sessionStorage.setItem('pos', document.body.scrollTop);
  }
 }

遇见了一个问题:

每次返回 List, 都是直接滚动到顶部, 每次都是, 每次都是! 把 pos 打印出来, 发现是 0, 而不是我们所存的值. 日了, 明明切换之前还是的, 回来就不是了.

然后发现了路由每次切换都会触发 onscroll 事件, 日了狗, 为毛.我都没有滚动页面, 为什么会触发 onscroll 事件。

刚开始怀疑 hash 变化会导致 onscroll 事件的触发, 所以我就在浏览器里面手动输入了几个不存在的路由:

/foo
/bar

没有发现 scroll 被触发, 所以这个嫌疑排出.

然后怀疑 vue-router 里面是不是绑定了 scroll 事件, 没发现然后又想, 没绑定 scroll 事件, 那么修改 scrollTop 值会不会也触发 scroll 事件.

好吧还发现新知识点了:

scrollTop 值的改变, 的确会触发 scroll 事件.

那么我就想, 是不是 vue-router 里面存在修改 scrollTop 值的行为, 也没有发现.

然后我又想, 数据是动态渲染的, 所以是不是和元素的增删改查相关。

元素增加-> 页面高度变了 -> 页面高度变化, 也触发 scroll 事件?

所以我用 vue-cli 新建了项目, 放了两个没有增删改查的路由

然后日了狗的, 我看见从 foo -> bar -> foo, 的时候, foo的滚动条位置还在之前我滚动到的地方.

突然想起来浏览器是可以自己记录滚动条位置的.

是不是浏览器干的?

从详情页返回到列表页面, 列表会重新渲染, 时序大概是这样:
返回列表页 1
渲染页面   2

而浏览器恢复滚动条的位置的操作, 是在 1 和 2 之间, 这个时候就出问题了:如果你页面上面的数据都是渲染出来的, 浏览器就会发现:

页面的高度<=屏幕的高度, 不存在滚动条, 此时 document.body.scrollTop = 0;
所以会设置 document.body.scrollTop = 0
修改了 document.body.scrollTop 触发了 scroll 事件, scroll 里面又重写了 pos

等你数据渲染结束之后, 读到的就是 0了.

如果发现你页面高度大于屏幕高度, 但是页面高度是 n, 而 pos 的值是: n + x, 比当前页面的最大的 scrollTop 值还大, 这个时候, document.body.scrollTop 的值就会等于 n.
当你的数据渲染结束, 开始定位, 日了, 没定准.

所以我们要解决这个问题.

当然是想到了 keep-alive, 刚启用的时候, 发现的确不错. 但是同时也发现:

列表项目靠前的, 往返操作的定位都很准, 越往后越不行, 直接拉到底, 再返回发现定位到的一般都是第二个第三个列表项目.

所以这个就很有意思了, 我大概猜测了一下浏览器的滚动位置恢复行为:

当 hashchange 的时候。拿到当前页面的 document.body.scrollTop 值, 和自己存储的滚动条位置。二者取最小的值, 设置成当前的 document.body.scrollTop 的值, 当使用 keep-alive 的时候, 因为 hashchange 事件处理和页面渲染是并行的, 所以有时hashchange 拿到的 document 的高度是已经渲染过几个元素的高度, 这个就是为什么定不准的原因.

好吧, 现在的情况是:

keep-alive 定不准, 不可靠, 所以需要我们自己来重新定位.

ok, 1 先绑定 scroll 事件:

 var map = {};
 window.onscroll = function() {
  map[location.hash] = document.body.scrollTop;
 }

2 再屏蔽掉浏览器自动恢复滚动位置行为带来的影响

a 在 hashchange 时强制 document.body.scrollTop = 0

b 在 scroll 事件里面, 当 document.body.scrollTop = 0 的时候不做 存操作.

 var map = {};
 window.onhashchange = function() {
  document.body.scrollTop = 0;
 }
 window.onscroll = function() {
  if (document.body.scrollTop) {
   // 存
   map[location.hash] = document.body.scrollTop;
  } else {
   // 读
  }
 }

3 在读操作里面, 设置一个定时任务, 去判断 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);
  }
 }

到这里实际上已经大体实现了, 返回恢复滚动条位置的功能, 而上面的代码需要更多的优化,

具体代码见:项目地址

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


# Vue固定滚动位置  # Vue页面滚动固定位置  # Vue实现渲染数据后控制滚动条位置(推荐)  # vue实现滚动条到顶部或者到指定位置  # vue中实现点击按钮滚动到页面对应位置的方法(使用c3平滑属性实现)  # vue监听页面中的某个div的滚动事件并判断滚动的位置  # Vue滚动到指定位置的多种方式示例详解  # Vue滚动页面到指定位置的实现及避坑  # Vue列表如何实现滚动到指定位置样式改变效果  # 解决vue无法设置滚动位置的问题  # vue通过滚动行为实现从列表到详情  # 返回列表原位置的方法  # vue-scroller记录滚动位置的示例代码  # Vue页面返回滚动位置恢复(keep-alive滚动记忆)  # 都是  # 滚动条  # 几个  # 就会  # 我用  # 不存在  # 好吧  # 这个时候  # 详情页  # 一个问题  # 绑定  # 而不是  # 如果你  # 是在  # 就在  # 还在  # 是有  # 是这样  # 我都  # 就不 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: Laravel如何实现登录错误次数限制_Laravel自带LoginThrottles限流配置【方法】  EditPlus中的正则表达式 实战(4)  如何用西部建站助手快速创建专业网站?  Laravel如何实现文件上传和存储?(本地与S3配置)  如何为不同团队 ID 动态生成多个“认领值班”按钮  如何在云服务器上快速搭建个人网站?  电视网站制作tvbox接口,云海电视怎样自定义添加电视源?  Laravel怎么实现支付功能_Laravel集成支付宝微信支付  html5源代码发行怎么设置权限_访问权限控制方法与实践【指南】  Android okhttputils现在进度显示实例代码  🚀拖拽式CMS建站能否实现高效与个性化并存?  Laravel怎么处理异常_Laravel自定义异常处理与错误页面教程  如何在服务器上三步完成建站并提升流量?  如何基于PHP生成高效IDC网络公司建站源码?  Edge浏览器提示“由你的组织管理”怎么解决_去除浏览器托管提示【修复】  Laravel如何使用withoutEvents方法临时禁用模型事件  Python高阶函数应用_函数作为参数说明【指导】  如何在服务器上配置二级域名建站?  如何在阿里云虚拟机上搭建网站?步骤解析与避坑指南  Laravel如何实现用户注册和登录?(Auth脚手架指南)  php嵌入式断网后怎么恢复_php检测网络重连并恢复硬件控制【操作】  高防服务器租用指南:配置选择与快速部署攻略  移动端手机网站制作软件,掌上时代,移动端网站的谷歌SEO该如何做?  Laravel怎么使用Markdown渲染文档_Laravel将Markdown内容转HTML页面展示【实战】  HTML 中动态设置元素 name 属性的正确语法详解  Laravel怎么自定义错误页面_Laravel修改404和500页面模板  如何自定义建站之星网站的导航菜单样式?  如何快速搭建个人网站并优化SEO?  Win11怎么设置虚拟桌面 Win11新建多桌面切换操作【技巧】  如何在Windows虚拟主机上快速搭建网站?  Windows11怎样设置电源计划_Windows11电源计划调整攻略【指南】  什么是JavaScript解构赋值_解构赋值有哪些实用技巧  如何挑选优质建站一级代理提升网站排名?  Python企业级消息系统教程_KafkaRabbitMQ高并发应用  韩国网站服务器搭建指南:VPS选购、域名解析与DNS配置推荐  如何在IIS中配置站点IP、端口及主机头?  HTML5建模怎么导出为FBX格式_FBX格式兼容性及导出步骤【指南】  Laravel中间件起什么作用_Laravel Middleware请求生命周期与自定义详解  宙斯浏览器怎么屏蔽图片浏览 节省手机流量使用设置方法  Laravel如何实现多语言支持_Laravel本地化与国际化(i18n)配置教程  Laravel如何使用Gate和Policy进行授权?(权限控制)  Laravel的Blade指令怎么自定义_创建你自己的Laravel Blade Directives  Laravel如何实现数据库事务?(DB Facade示例)  Laravel如何自定义分页视图?(Pagination示例)  Laravel如何与Inertia.js和Vue/React构建现代单页应用  如何用狗爹虚拟主机快速搭建网站?  Windows10电脑怎么查看硬盘通电时间_Win10使用工具检测磁盘健康  Laravel如何使用Service Provider注册服务_Laravel服务提供者配置与加载  购物网站制作费用多少,开办网上购物网站,需要办理哪些手续?  JavaScript 输出显示内容(document.write、alert、innerHTML、console.log)