vue 中 使用better-scroll 时因为图片没有下载完导致滚动条高度不够,无法浏览全部内容

解决vue 中 使用better-scroll 时因为图片没有下载完导致滚动条高度不够,无法浏览全部内容的问题

better-scroll 是根据 scrollerHeight 属性决定有多少区域可以滚动的。

scrollerHeight 属性是根据放 better-scrol 的 content 中的子组件的高度来计算的。
better-scroll 初始化是在dom 加载后执行,此时图片没有下载完成,计算 scrollerHeight 属性时,是没有将图片高度计算在内的。所以,计算出来的结果是错误的。
后来图片加载进来之后content 有了新的高度,但是 scrollerHeight 属性并没有进行更新,所以滚动出现了问题

解决方法就是调用better-scroll 的refresh 函数去刷新高度。

假设组件树是这样的:
组件树

  • 第一种方式

    可以看到,需要滚动的组件都会包含在Scroll 组件中。可以在Scroll 组件中的updated 生命周期函数中检测滚动区域内的图片是否加载完成,当全部图片加载完成时,调用refresh 函数重新计算scrollerHeight

    mounted() {
      this.bs = new BScroll(this.$refs.scroll, {
        click: true
      });
    },
    updated() {
      // 利用图片的complete 属性进行判断,当所有图片下载完成后再对scrollerHeight 重新计算。
      let img = this.$refs.scroll.getElementsByTagName("img");
      let count = 0;
      let length = img.length;
      if (length) {
        let timer = setInterval(() => {
          if (count == length) {
            this.bs.refresh();
            clearInterval(timer);
          } else if (img[count].complete) {
            count++;
          }
        }, 100);
      }
    }
    
  • 第二种方式,原生js 监听图片加载事件img.onload = function()(Vue 中提供了@load 事件,效果相同)

    从组件树中可以看到,对GoodsListItem 中的img 元素添加load 时想要拿到Scroll 组件中的better-scroll 对象需要一层一层传递下来
    而对load 事件的处理最好放在Home 组件的created 钩子函数中,想要把load 事件传递出去也比较麻烦
    像这种非父子组件之间的通信,可以使用事件总线$bus 来传递事件

    // 1. 在mian.js 中添加事件总线
    Vue.prototype.$bus = new Vue()
    
    // 2. 对GoodsListItem 组件中的img 元素监听load 事件
    <img @load="imgLoaded">
    
    // 3. 在GoodsListItem 组件中使用事件总线提交事件
    methods: {
      imgLoaded() {
        this.$bus.$emit('imgLoaded')
      }
    }
    
    // 4. 在Home 组件中监听imgLoaded 事件(Home 组件中可以直接拿到Scroll 组件中的better-scroll 对象),并调用better-scroll 的refresh 函数去刷新高度
    mounted() {
      this.$bus.$on('imgLoaded', () => {
        this.$refs.scroll.refresh()
    })
    

注意,第二种方式存在refresh 函数调用频繁的问题,有多少张图片触发load 事件就会调用多少次

解决方法就是添加防抖动函数debounce

methods: {
  debounce(func, delay) {
    /**
     * 防抖动,防止函数频繁调用
    */
    let timer = null
    return function (...args) {
      if (timer) clearTimeout(timer)
      timer = setTimeout(() => {
        func.apply(this, args)
      }, delay)
    }
  }

mounted() {
  const refresh = debounce(this.$refs.scroll.refresh, 50)
    this.$bus.$on('imgLoaded', () => {
      refresh()
  })
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值