目前的解决方案是结合 better-scroll 的滚动插件----原因是 better-scroll 把原生滚动封装的比较好 对于移动端和PC滚动算是不错的选择
<template>
<div class="vue-virtual-collection" :style="outerStyle" ref="outer">
// 使用 better-scroll 封装的一个滚动骨架组件
<vertical-scroll :listenScroll="true"
:probeType="3"
:bounce="false"
@scroll="verticalScroll">
<div class="vue-virtual-collection-container" :style="containerStyle">
<div class="cell-container" v-for="(item, index) in displayItems"
:key="item.index"
:style="getComputedStyle(item, index)" ref="cellContainer">
<slot name="cell" :data="item"></slot>
</div>
</div>
</vertical-scroll>
</div>
</template>
<script type="text/ecmascript-6">
import VerticalScroll from "base/VerticalScroll";
export default {
methods: {
init () {
// 设置当前视图我们中应该显示那些块
this.flushDisplayItems(0, 0);
},
// 获取到视图应该渲染那些块之外我们还需要设置这些块所应该在的位置
getComputedStyle (displayItem) {
if (!displayItem) {
return;
}
const {width, height, x, y} = this._sectionManager.getCellMetadata(displayItem.index);
return {
transform: `translate3d(${x}px, ${y}px, 0)`,
width: `${width}px`,
height: `${height}px`
}
},
// 设置当前视图我们中应该显示那些块
flushDisplayItems (x, y) {
let scrollLeft = x;
let scrollTop = Math.abs(y);
// 然后这里我们需要去设置当前视图中应该渲染那些块
// 于是我们要在 SectionManager类中定义一个方法去获取需要渲染的那个块的索引
let indices = this._sectionManager.getCellIndices({
height: this.height,
width: this.width,
x: scrollLeft,
y: scrollTop
});
// 到这里我们已经获取到了索引了,然后我们就可以去渲染该视图所对应的块了
const displayItems = [];
indices.forEach(index => {
displayItems.push({
index,
...this.collection[index]
})
});
// 重新渲染数据
this.displayItems = displayItems;
},
// 滚动骨架组件监听滚动的方法-垂直滚动
verticalScroll (pos) {
this.flushDisplayItems(pos.x, pos.y)
}
},
components: {
VerticalScroll
}
}
</script>
<style lang="stylus">
.vue-virtual-collection {
overflow: hidden;
-webkit-overflow-scrolling: touch;
height: 100%;
width: 100%
}
.vue-virtual-collection-container {
position: relative;
overflow: hidden;
}
.cell-container {
position: absolute;
top: 0;
overflow: hidden;
}
</style>