Better-Scroll组件封装--Vue使用Better-Scroll异步加载数据时页面无法下拉滚动的问题

--新增:该解法在单页面时可用,但

  • 当页面中内容有图像等时,直接在数据设置前调用refresh,此时图像等元素还未渲染成功,refresh不能正确计算scrollerHeight。
  • 当页面内容有切换时,数据是在最早就一起设置了,但页面切换时才开始第一次渲染元素,这时refresh未被调用,当前的滚动高度scrollerHeight也会与页面不相符。

解决方式: 监听图像的渲染结束事件onLoad,结合vuex/或事件总线bus在父组件中调用refresh。 并通过防抖函数debounce实现性能优化。
见文

问题

使用Better-Scroll做项目,普通html和普通的Vue页面测试都可以正常滚动,但简单封装一层以后在Vue页面里就没法用了。

DOM查看对应的列表,发现Better-Scroll管理下的列表高度为0。 一开始以为是样式的问题,改了好久也没办法,但把数据设置为静态列表时发现正常滚动,应该是数据加载的问题。

原因

Better-Scroll实例bscroll的初始化,虽然是在组件的mounted中写的,保证了DOM渲染已完成,但列表内的数据项是由异步网络请求获取到数据后,动态生成的,这之后bscroll并没有重新计算滚动部分的高度。
因而导致了无法滚动的问题。

解决

1. 手动设置延时n秒后调用bscroll.refresh()。-- 不具备通用性,时间不可控。
2. 封装的Scroll组件公开一个refresh方法,父组件的数据获取并设置之后,手动调用refresh。

- Scroll.vue

  • 参考Better-Scroll作者的文章--当 better-scroll 遇见 Vue
  • 通过 props 的形式,把一些对 better-scroll 定制化的控制权交给父组件;
  • 通过 methods 暴露的一些方法对 better-scroll 的方法做一层代理;
  • 通过 watch 传入的 data,当 data 发生改变的时候,在适当的时机调用 refresh 方法重新计算 better-scroll 确保滚动效果正常
/**
 * Better-Scroll封装
 */
<template>
  <div class="wrapper" ref="wrapper">
    <div class="content">
      <slot></slot>
    </div>
  </div>
</template>

<script>
import BScroll from 'better-scroll'

export default {
  name: "Scroll",
  props: {
    probeType: {
      type: Number,
      default: 0
    },
    pullUpLoad: {
      type: Boolean,
      default: false
    },
    /**
     * 当数据更新后,刷新scroll的延时。
     */
    refreshDelay: {
      type: Number,
      default: 20
    }
  },
  data() {
    return {
      bscroll: null
    }
  },
  mounted() {
    // 保证在DOM渲染完毕后初始化better-scroll
    setTimeout(() => {
      this._initScroll()
    }, 20)
  },
  methods: {
    _initScroll() {
      if (!this.$refs.wrapper) {
        return
      }

      // 1.创建BScroll对象
      this.bscroll = new BScroll(this.$refs.wrapper, {
        click: true,
        mouseWheel: true,
        bounce: {
          top: false
        },
        probeType: this.probeType,
        pullUpLoad: this.pullUpLoad
      })

      // 2.监听事件设置
        //...
    },

    refresh() {
      // 代理better-scroll的refresh方法
      this.scroll && this.scroll.refresh()
    }
  },
  watch: {
    // 监听数据的变化,延时refreshDelay时间后调用refresh方法重新计算,保证滚动效果正常
    data() {
      setTimeout(() => {
        this.refresh()
      }, this.refreshDelay)
    }
  }
}
</script>
<style scoped>
</style>

- Home.vue中

  • 通过prop传递scroll的配置和数据,并在合适的时机调用子组件的refresh即可。
<template>
  <div id="home">
    <scroll class="content" ref="scroll" :probe-type="3">
      <good-list :goods="showGoodsList"></good-list>
    </scroll>
  </div>
</template>
<script>

import Scroll from 'components/common/scroll/Scroll'
export default {
  components: {
    Scroll,
    //...
   },
  created() {
    this.getData();
  },
  methods() {
    getData(){
     requestData().then((res) => {
         //设置数据
        //调用bsscroll的更新
        this.$nextTick(() => {
          this.$refs.scroller.refresh();
        })
      })
    }
  }
}
posted @ 2021-02-19 10:24  朝日asahi  阅读(425)  评论(0编辑  收藏  举报