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();
})
})
}
}
}