看了很多大佬写的虚拟列表渲染,跟着实现了一次加深理解

54 阅读1分钟

//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; }