better-scroll和vue-router中scrollBehavior不兼容处理

在做一个实战项目时,首页是一个商品列表页,引入better-scroll实现滚动效果


 import BScroll from 'better-scroll';
mounted() {
      this._initScroll();
    },
methods: {
      _initScroll() {
        this.$nextTick(() => {
          this.BScroll = new BScroll(this.$refs.container,{
            click: true,
            probeType: 3
          });
          this.pageOnScroll();
        });
      }
    },

点击商品,跳转至商品详情页,返回时想要页面滚动到之前所在的位置,首先会想到vue-router的scrollBehavior方法

scrollBehavior(to, from, savePosition) {
    if(savePosition) {
      return savePosition
    }else {
      return {
        x: 0,
        y: 0
      }
    }
  }

但效果却没出来,打印savePosition查看,显示为0和0



查询官方文档:

使用前端路由,当切换到新路由时,想要页面滚到顶部,或者是保持原先的滚动位置,就像重新加载页面那样。 vue-router 能做到,而且更好,它让你可以自定义路由切换时页面如何滚动。

可以看到,官方的方法是记录整个页面的滚动,意思是,页面是由内容自动撑高的,高度不固定。但是要使用better-scroll,就必须将外围包裹层高度固定下来,这是better-scroll的滚动原理决定的


当滚动体高度覆盖了整个页面的时候,父级包裹层的高度就必须固定为屏幕的高度

.container{
    width: 100%;
    position: absolute;
    left: 0;
    top: 2.2rem;
    bottom: 0;
    overflow: hidden;
  }

所以,整个页面的高度是固定的,不会出现页面滚动的情况,滚动的是内部的子元素,这也就难怪返回的滚动距离为0了

由于better-scroll提供了on事件的监听,可以获取滚动的距离,可以帮助实现这个效果

刚开始想着用vuex来全局存储滚动距离,既然vue-router自带的方法无法存储滚动距离,那就用better-scroll的方法获取到,然后存到全局,在监听到返回事件的时候赋值给返回值

store/index.js

import Vuex from 'vuex'
import Vue from 'vue'

Vue.use(Vuex);

const store = new Vuex.Store({
  state: {
    mallScrollY: 0
  },
  mutations: {
    scroll(state, posY) {
      state.mallScrollY = posY;
    }
  }
});

export default store

ShoppingMall.vue

import {mapMutations} from 'vuex'

这样就把滚动距离存到了全局,在路由页面获取距离

router/index

import Store from '@/store/index'
scrollBehavior(to, from, savePosition) {
    if(savePosition) {
      return {
        x: 0,
        y: Store.state.mallScrollY
      }
    }else {
      return {
        x: 0,
        y: 0
      }
    }
  }

但是想法很美好,结果很悲催哭

依然没有效果,发现还是那个问题,vue-router的scrollBehavior通过监听页面滚动事件来记录滚动距离,那么返回的值也是页面应该滚动的距离,前面已经把页面高度固定了,再怎么赋值也无法滚动了。

于是只能全靠better-scroll了,还好,有scrollTo方法可以用

因为页面用了keep-alive缓存数据,所以页面跳转离开后,原页面的数据不会销毁

这样就可以把滚动数据存储在当前页面,待跳转返回来的时候拿到数据,利用better-scroll的scrollTo方法,滚动到先前的位置

pageOnScroll() {
        let that = this;
        this.BScroll.on('scroll', (pos) => {
          console.log(pos.y)
          that.scrollY = pos.y;
        })
      }

返回的时候,监听路由变化

watch: {
      '$route'(to, from) {
        let that = this;
        if(to.name === 'ShoppingMall') {
          if(this.BScroll) {
            that.BScroll.scrollTo(0, that.scrollY, 10)
          }
        }
      }
    }

但是返回的时候,不断触发pageOnScroll函数


进入死循环,点击页面立刻就回到了顶部

后来发现,应该是由于页面缓存,之前绑定的on事件没被清除,返回时调用scrollTo方法,滚动到目标距离的过程中就会不断触发on事件,导致死循环

处理方法:

返回后先刷新一下,再滚动到目标距离

watch: {
      '$route'(to, from) {
        let that = this;
        if(to.name === 'ShoppingMall') {
          if(this.BScroll) {
            this.BScroll.refresh(); // 必须先刷新一下,不然报错
            that.BScroll.scrollTo(0, that.scrollY, 10)
          }
        }
      }
    }
这样就ok了














发布了59 篇原创文章 · 获赞 29 · 访问量 15万+

猜你喜欢

转载自blog.csdn.net/dongguan_123/article/details/80914225