<div class="drawerList" @scroll="testScroll">//最外层div,高度大小一般和可视div高度一致
<div class="drawerList_div"></div>//占位div
<div class="drawerList_content" :style="`transform:${getTransform}`">//可视div
<div class="drawerItem" v-for="(item,index) in showList(drawerTitle)" :key="index">
...渲染数据
<div>
<div>
<div>
<script setup>
const startOffset = ref(0)
//translate3d且因为没有重排重绘,所以性能更好
//getTransform 计算的高度为当前界面想展示出来的高度,即为可视div的高度
const getTransform = computed(() => {
return `translate3d(0,${startOffset.value}vw,0)`
})
const start = ref(0)//可视div渲染出来的第一个元素的下标,做个标记
const testScroll = (event) => {
let scrollTop = event.target.scrollTop//滚动距离
start.value = Math.floor(scrollTop / 247) * 3//这里的247是我这边每个item的高度,除以3是因为每行有3个,每行一个则不需要除以3
startOffset.value = ((scrollTop - (scrollTop % 247)) / 17.65625)//这里除以17.65625是我想px单位转为vw单位做兼容用的,直接用px单位的话直接 = scrollTop - (scrollTop % 247)就行
}
//展示在可视div的数据(我这里的cartList和historyList是根据不同接口返回的总数据源)
const showList = computed(() => {
return (drawerTitle) => {
if (drawerTitle==='已选款') {
return cartList.value.slice(start.value,start.value+9) //这里+9是我的可视div,一屏可以看到9条
} else {
return historyList.value.slice(start.value,start.value+9)
}
}
})
<script setup>
css部分
.drawerList{
width:100%;
height: calc(100% - 7.8vw);//必须写个固定高度
overflow-y: auto;//让下方占位的div撑大,出现滚动条
position: relative;//这个想对定位的处理是让下方可视div可以相对滚动
.drawerList_div{//此div为占位div,
width: 100%;
height: 1000vw;//临时测试写的高度,实际开发过程中需用计算属性计算,计算方式根据你布局的方式(ex:一行一个item,则高度为item的高度*item的总个数;如果一行为3个item,则高度为每行的高度*item的总条数/3,我这里就是每行为3个的布局)
position: absolute;
left: 0;
top: 0;
z-index: -1;
}
.drawerList_content{//可视div
display: flex;
flex-wrap: wrap;
padding: 17px 32px;
width:100%;
height: 100%;
padding-right: 18px;
.drawerItem{//item数据
background: #FFFFFF;
border: 1px solid rgba(221,221,221,1);
border-radius: 4px;
margin-bottom: 12px;
margin-right: 9px;
width: calc(33.3% - 10px);
margin-right:10px;
overflow:hidden;
height: fit-content;
}
}
记录-前端性能优化之虚拟列表加载(vue3)
于 2023-12-27 14:55:26 首次发布