2025年3月23日 星期日 甲辰(龙)年 月廿二 设为首页 加入收藏
rss
您当前的位置:首页 > 计算机 > 编程开发 > JavaScript

vue-router 中 scrollBehavior 的妙用

时间:12-14来源:作者:点击数:9
CDSY,CDSY.XYZ

1. keep-alive

问题:使用 keep-alive 标签后部分安卓机返回缓存页位置不精确问题

解决方案:

  • <div>
  • <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 };
  • },
  • });

2. 页面返回出现空白屏问题

问题

  • 【前提】:iOS设备
  • 【步骤】: 页面A是个列表很长-->滑到页脚的时候点击跳转之后到页面B--->再返回A页面
  • --->屏幕会出现空白遮罩层--->手指轻触屏幕滑动--->遮罩层消失

解决方案一

在接口请求成功后的回调操作完成后进行该操作,例如

  • // fetchCourseList是一个封装好的Promise请求
  • fetchCourseList().then(({ data: courses }) => {
  • this.courses = courses;
  • }).then(() => {
  • setTimeout(() => {
  • window.scrollTo(0, 1);
  • window.scrollTo(0, 0);
  • });
  • });

该方案的弊端:每个页面都需要做这样的处理,不推荐使用。

解决方案二(推荐)

使用 scrollBehavior 中的异步滚动操作

  • 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 的滚动位置。

这里为什么不能直接 return 而必须使用异步滚动操作呢?以下是个人的一些见解欢迎大家来探讨指正。
  1. 首先我们要先去了解 scrollBehavior 函数究竟在组件的哪个生命周期后才开始执行。这里我对组件的每个生命周期和scrollBehavior函数进行alert,经排查结果:scrollBehavior函数在组件的生命周期mounted后beforeUpdate前执行。
  2. 在 scrollBehavior 函数中直接 return{ x:0, y:100} ,进入页面仍在顶部。为什么不会滚动到100px处?猜测:mounted中的异步请求回来的数据赋值给 data 中的变量a,变量a因为vue的双向绑定更新了view层而引起滚动失效?
  3. 验证下以上的猜测,设置一个静态页面数据都已经在html上写死。scrollBehavior 函数中直接 return { x:0, y: 100} ,结果:进入页面都会滚动到100px处。证明:确实与异步请求回来后的操作有关系。
  4. 接着了解 vue 的 mounted 和 beforeUpdate 时期都做了些什么。mounted 时期 :data 数据已经挂在到页面上。beforeUpdate 和 updated 时期:当vue发现data中的数据发生了改变,会触发对应组件的重新渲染。
  5. 根据步骤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 数据发生改变,页面重新渲染又回到顶部。这时整个轻触滚动效果已经暗中执行完成,不会再出现遮罩层了。

CDSY,CDSY.XYZ
方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门
本栏推荐