问题:使用 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 };
- },
- });
问题
- 【前提】: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 的滚动位置。
必须使用异步滚动,利用 setTimeout 跳出主线程将回调事件放到队列中。由于 mouted 比 scrollBehavior 函数早执行,所以异步请求的回调事件优先进入队列,接下去才是 setTimeout 的回调事件。根据队列 先进先出的原理。先执行了异步请求回调事件对 data 中的变量a做赋值操作。此时相当于这已经是个静态页面了,接着我只要执行return { x:0, y: 100 }。这样就已经触发了页面滚动到 100px 的效果。但是由于 data 数据发生改变,页面重新渲染又回到顶部。这时整个轻触滚动效果已经暗中执行完成,不会再出现遮罩层了。