问题分析
- BetterScroll 实例有一个
scrollerHeight
属性,用于定义可滚动区域的高度。 - 该属性的值取决于 BetterScroll 内容区(content)中所有子组件的高度总和。
- 当子组件中的图片在网络请求完成后渲染的时间超过了
scrollerHeight
计算的时间,这会导致 scrollerHeight
的值未能包含图片的高度,从而引起页面无法正常滑动或滑动卡顿。 - 即使图片加载完成后,
scrollerHeight
的值也不会自动更新,需要手动处理。
解决方案
- 监听每张图片的加载完成事件,每加载完一张图片即调用
refresh()
方法,以重新计算 scrollerHeight
。 refresh()
方法能够重新评估滚动区域的高度,确保滚动功能正常。
方法一:使用Vuex管理状态
在 Vue 组件内,可以在 img
标签上监听 load
事件,当图片加载完成后调用 Vuex 中的 refresh
方法。
<img :src="item.image" @load="imageLoad">
methods: { imageLoad() { this.$store.dispatch('refreshScroll'); } }
在 Vuex store 中定义一个 action 来处理 refresh
调用:
import { createStore } from 'vuex'; export default createStore({ state: { scrollInstance: null }, mutations: { setScrollInstance(state, instance) { state.scrollInstance = instance; } }, actions: { refreshScroll({ state }) { if (state.scrollInstance) { state.scrollInstance.refresh(); } } } });
方法二:使用事件总线
对于 Vue 3 及以上版本,可以使用第三方库 mitt
来实现事件总线的功能。
首先,在 main.js
文件中设置事件总线:
import { createApp } from 'vue'; import App from './App.vue'; import router from '@/router'; import mitt from 'mitt'; const app = createApp(App); app.use(router).mount('#app'); app.config.globalProperties.$bus = new mitt();
然后,在需要监听图片加载的组件中使用事件总线:
<img :src="goodshow.show.img" @load="imageLoad">
methods: { imageLoad() { this.$bus.emit('imageLoaded'); } }
最后,在需要响应图片加载事件的组件中监听并处理:
mounted() { this.$bus.on('imageLoaded', () => { if (this.$refs.scroll && this.$refs.scroll.scroll) { this.$refs.scroll.scroll.refresh(); } }); }
性能优化
- 频繁调用
refresh()
会影响应用性能,可以通过防抖技术减少调用次数。
例如,可以使用防抖函数来限制 refresh()
的调用频率:
mounted() { function debounce(func, delay) { let timer = null; return function(...args) { if (timer) clearTimeout(timer); timer = setTimeout(() => func.apply(this, args), delay); } } const refresh = debounce(this.$refs.scroll.refresh, 50); this.$bus.on('imageLoaded', () => { refresh(); }); }