//ps:本人新手如有问题,敬请原谅,如果能指出更是感激不尽,o( ̄▽ ̄)ブ //在此特别感谢能在掘金上发文章的各位大佬,你们分享知识对我这样的小白新人真的是有非常大的帮助!!!
js部分
`import { computed, onMounted, ref } from 'vue';
const listData = Array.from({length:10000}).map((item,index)=>{
return {id:index,value:item---${index}}
})
//初始化完成 容器高度设置 const container = ref(null)
const containerHeight = ref(0)
const placeholder = ref(null)
const itemHeight = ref(200)
const listDataLength = listData.length
onMounted(()=>{ containerHeight.value = container.value.clientHeight placeholder.value.style.height = itemHeight.value*listDataLength + 'px' })
//展示的第一个item的索引,默认为0
const start = ref(0)
//计算内容区要展示的数据
//根据容器高度计算出可视区域每次能展示多少个item,避免有一半在可视区域,一半不在的情况
//计算时向上取整
const itemCount = computed(()=>{
return Math.ceil(containerHeight.value/itemHeight.value) })
//根据开始位置和展示个数计算出最后一个item的索引 const end = computed(()=>{ return start.value + itemCount.value
})
//有开始索引和结束索引就知道每次渲染的item数组
//这里我们加二表示多截取两个防止滑动过快出现加载不及时有空白
const renderList = computed(()=>{
return listData.slice(start.value,end.value+2)
})
const translate = ref(0)
//当触发滚动时,要处理一下部分,start,end,获取滚动距离计算偏移量
function ScrollHandle(e){
let scrollTop = e.target.scrollTop
start.value = Math.floor(scrollTop/itemHeight.value)
translate.value =scrollTop - scrollTop%itemHeight.value
console.log(translate.value)
console.log(start.value,'---',end.value)
console.log(renderList.value)
}
//当滚动时内容区会随着一起滚动走,这就导致触发滚动事件时,虽然内容区渲染的item更新了,但是
//内容区滚动走了,可视区展示的数据就越来越少,所以当触发滚动,滚动走多少个距离,就让内容区 //移动回来多少个距离,
const styleObj = computed(()=>{
console.log(translateY(${translate.value}px))
return {
transform:translateY(${translate.value}px)
} })
//优化:
//滚动事件触发太频繁了
//throttle一下
//不知道这段代码有没有问题[狗头]
function throttle(fn,delay){
let lastStartTime = Date.now();
let clear;
return function (e){
function run(){
let current = Date.now()
if(current-lastStartTime>=delay){
lastStartTime = current
console.log(1)
fn(e)
}else{
return
}
}
run()
} }
const thrScrollHandle = throttle(ScrollHandle,100)`
html部分
<div ref="container" class="container" @scroll="thrScrollHandle($event)">
<div ref="placeholder" class="placeholder"></div>
<div class="content" :style="styleObj">
<div :style="{height:'200px'}" class="item" v-for="i in renderList" :key="i.id">
{{ i.value }}
</div>
</div>
</div>
</div>
样式
.container{ width: 100vw; height:100vh; padding:0 50px; overflow: auto; position: relative; } .placeholder{ width:1px; position: absolute; } .item{ background:#fff; color:#000; padding:10px; display: flex; justify-content: center; align-items: center; border:1px solid #000; margin:10px; }