写在开头
学习之余,发现了一个比较好的滚动组件 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"
的方式来监听。步骤如下:
- 在包含<img> 的 Vue 子组件中,通过
@load="isLoadOK"
的方式来监听图片是否加载完成; - 在 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()
})
}
}
参考文章:
博主写作不易,加个关注呗
求关注、求点赞,加个关注不迷路 ヾ(◍°∇°◍)ノ゙
博主不能保证写的所有知识点都正确,但是能保证纯手敲,错误也请指出,望轻喷 Thanks♪(・ω・)ノ