解决vue引入BetterScroll导致的图片列表拉不上去问题

写在开头

  学习之余,发现了一个比较好的滚动组件 BetterScroll,在移动端、PC端都有很好的体验效果。就拿出来分享一下:BetterScroll官网。源码托管自 GitHub:BetterScroll。中文文档:BetterScroll文档

  该组件在 GitHub 有这样依据介绍:inspired by iscroll, and it supports more features and has a better scroll perfermance.(灵感来源于iscroll...)。iscroll 也是一个比较好的滚动组件,但是在 3 Jan 2017停更了。所以在这之后,国人就开发了 BetterScroll 这么一个优秀的组件,截止2020.7.1还在继续更新,而且该组件在 iscroll之上也添加了更多的一些功能,效果还是不错的。

图片列表拉不上去的原因

  在开发中,总会遇到对图片列表的上拉加载需求。但是在引入 BetterScroll 组件时,却 导致图片类型列表上拉到一部分时,出现拉不上去的Bug。

  经过分析,是Vue在加载数据的过程中,由于网络的原因,图片的加载都会有个先后顺序(或因为网络延迟,导致的图片迟了几百毫秒显示)。然而 BetterScroll 组件是在图片还未加载完成时,就已经完成了对滚动区域的高度计算,当图片真正加载完成时,导致高度计算有问题,从而出现拉不上去的Bug。 (实际高度>已计算的高度,导致拉不上去)

解决办法

  BetterScroll 组件中,提供了refresh()这个方法,即:重新计算 better-scroll,当 DOM 结构发生变化的时候务必要调用确保滚动的效果正常。

  最终解决方法就是:在每次加载图片完成时,重新计算一下 DOM 结构的高度。

  原生JS在<img onload="xxx">标签中,onload 这个属性就是用来监听图片是否加载完成的。Vue 中我们可以通过 @load="xxx" 的方式来监听。步骤如下:

  1. 在包含<img> 的 Vue 子组件中,通过 @load="isLoadOK" 的方式来监听图片是否加载完成;
  2. 在 methods 中定义方法 isLoadOK ,然后通过 $emit 的方式,将事件传到父组件(兄弟组件请使用bus总线),父组件通过 this.$on() 的方式调用 this.refs.scroll.refresh() 就可以完美解决。

伪代码如下 (思想是这般,不好原样提供代码,就上面两个步骤就能解决的)

<!-- 子组件 -->
<template>
	<div class="goods-item" @click="itemClick">
    	<img :src="goodsItem.show.img" alt="" @load="isLoadOK">
  		<p>其他文字介绍</p>
  	</div>
</template>
<script>
  	export default {
  		name: 'scroll ',
  		//省略部分代码
  		methods:{
  			isLoadOK() {
		        this.$emit('imageLoad');
			}
		}
  	}
</script>
<!-- 父组件 -->
<template>
	<div id="home" class="wrapper">
		<!-- 引入子组件(此处是伪代码) -->
		<scroll ref="scroll"></scroll>
	</div>
</template>
<script>
  	export default {
  		//省略部分代码
  		//在加载完成时,
		mounted(){
			this.$on('imageLoad', this.$refs.scroll.refresh())
		}
  	}
</script>

上面方式,会引出性能问题

  如果一张图片加载完成就调用一次 refresh()方法,显然影响性能。此处我们可以使用 JS防抖函数来处理。

  所谓防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。

/**
 * 定义防抖动函数,防止函数调用频繁,图片加载完成后,再进行重新计算高度的刷新
 */
export  function debounce(func, delay) {
    let timer;
    return function(...args) {
        if (timer) clearTimeout(timer);

        timer = setTimeout(() => {
            func.apply(this, args)
        }, delay)
    }
}

  然后,将父组件中,this.$on('imageLoad', this.$refs.scroll.refresh()) 这种方式稍微修改一下即可,如下所示:

<script>
export default {
  	//省略部分代码
  	//在加载完成时,
	mounted(){
		// 1.图片加载完成的事件监听
      	const refresh = debounce(this.$refs.scroll.refresh, 50)
      	this.$on('imageLoad', () => {
        	refresh()
      	})
	}
 }

参考文章:

  JS 防抖函数和节流函数介绍


博主写作不易,加个关注呗

求关注、求点赞,加个关注不迷路 ヾ(◍°∇°◍)ノ゙

博主不能保证写的所有知识点都正确,但是能保证纯手敲,错误也请指出,望轻喷 Thanks♪(・ω・)ノ

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

扛麻袋的少年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值