<template>
<div class="home">
<div class="warp" ref="warp" @scroll="jko()">
<!-- 为了显示滚动条 -->
<div ref="scrollHeight"></div>
<div class="fry" :style="{transform: `translateY(${mko}px)`}">
<div v-for="(item,index) in visibleData" :key="index">{{item}}</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
},
data(){
return{
shim:Array(100).fill("kkkkkkk"),
size:20,//已知的元素的高度或者预估高度
hjk:'',
lop:8,//这个是我们希望显示的元素条数
start:0,//这个是选取的slice的第一个值,初始为0
mko:0,//这个是让可显示的区域一直跟随着滚动而变化的值
end:this.lop,//这个是选取slice的第二个值,也就要显示元素的最大范围
variable: true, // 每一项是否高度固定,这是第二种情况
positionListArr:[],
prevCount:0
}
},
mounted(){
this.$refs.warp.style.height=this.lop*this.size+'px'
//这里是为了扩充内容区域,怕不显示 ,算是一种优化
this.$refs.scrollHeight.style.height=this.shim.length*this.size+'px'
//缓存每一项元素的高度
this.mkomlp()
},
computed:{
visibleData() {
/*// 下面有用到 Math.min 是防止前面或后面没有 this.keeps 项,也就是刚开始或快到底的情况
const prevCount = Math.min(this.start, this.lop) // 展示的项数之前多渲染几项
this.prevCount = prevCount // handleScroll 方法里要用
const renderStart = this.start - prevCount // 真正的渲染开始项
const nextCount = Math.min(this.shim.length - this.end, this.lop) // 展示的项数之后多渲染几项
const renderEnd = this.end + nextCount // 真正的渲染结束项的后一项,因为 slice 是不包括 end 参数的*/
return this.shim.slice(this.start,this.end)
}
},
methods:{
jko(){
const ko=this.$refs.warp.scrollTop
if(this.variable){//这是不确定高度的情况
//首先再高度不确定的时候,思路是一样的,要先查找到动态的start
this.start=this.getStartIndex(ko) // 获取开始展示的那一项的下标
console.log(this.start)
this.end = this.start + this.lop
console.log(this.end)
// 下面这句用三元运算符是因为 this.positionListArr[this.start - this.prevCount] 的值可能为 undefined,
// 比如当从下往回滚动的时候 this.prevCount 的值有可能会有等于前一次滚动时的 this.start 的值的时候,大于现在 this.start 的值
this.mko = this.positionListArr[this.start+1].top
console.log(this.mko)
}else{//这是高度确定的情况
this.start=Math.ceil(ko/this.size)-1 >=0 ? Math.ceil(ko/this.size)-1:0
this.end=this.start+this.lop
this.mko=this.start * this.size
}
},
getStartIndex(scrollTop) {
//这里的二分法其实是说,在每次滚动的时候都找到我们与scrollTop相近的值,然后返回这个值
//然后让temp保存最相近的那一项
用二分法查找滚动距离是 positionListArr 哪一项的 bottom 的值
var startm=0//这个代表positionListArr的数据的第一项
var endb=this.positionListArr.length-1//代表最后一项的坐标
// 用 temp 存储得不到精确值时最终返回的值,因为可能滚动的距离的值不会等于 positionListArr 数组里
// 任何一项的 bottom 的值,所以只好存储一个最接近的值
var temp=null
while(startm <= endb){
let kop=parseInt(startm+(endb-startm)/2)//这一步是得到中间那一项的index值
var nmlo=this.positionListArr[kop].bottom//这一步是得到中间的那一项的bottom的距离顶部的值
//这一步是我们当在上面隐藏的区域等于我们当前中间项的bottom的值时
if(scrollTop==nmlo){
// 滚动的值刚好等于中间那一项的 bottom 值,则此时的展示起点 start 应该为中间那一项的下一项
return kop+1
}else if(scrollTop<nmlo){//这里时让他往上找还是往下找
// 滚动的值小于中间那一项的 bottom 值:
endb=kop-1
if (temp === null || temp > kop ) // temp >kop 保证了目标值所在范围越变越小
temp = kop
}else if(scrollTop > nmlo){
// 滚动的值大于中间那一项的 bottom 值:
startm=kop+1// 让 start 移动到中间的那一项的后面一项
if (temp === null || temp > kop ) // temp >kop 保证了目标值所在范围越变越小
temp = kop
}
}
return temp
},
//缓存this.shim的每一项的高度,top和bootom
// 注意: () => ({}) 为返回对象的写法
mkomlp(){
this.positionListArr=this.shim.map((item,index)=>({
height: this.size,
top: index * this.size,
bottom: (index + 1) * this.size
}))
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.warp{
width: 500px;
overflow: scroll;
position: relative;
}
.fry{
width: 100%;
position: absolute;
top: 0px;
left: 0;
}
</style>