按照惯例:如何一次性加载30w条数据并且滚动不卡顿呢
直接上代码:
<template>
<div>
<div>{{list.length}}条数据</div>
<div>{{startIndex}}-{{endIndex}}</div>
<div class="wrap" :style="{'height':wrapHeight+'px'}" @scroll="scrollWrap" ref="refWrap">
<div :style="{'height':(list.length*30).toString()+'px','position':'relative'}">
<template v-for="(item,index) in listComputed" :key="index">
<div class="list" :style="{'height':item.height+'px','top':'0px','transform':`translateY(${item.top}px)`}">
<span>{{item.text}}</span>
</div>
</template>
</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, ref, onMounted, computed, reactive, Ref, onActivated } from 'vue'
import { ListItems } from "./interface/index"
export default defineComponent({
name:"dynamicViews_three_index",
setup(prop, context) {
const list = reactive<ListItems[]>([])
const wrapHeight = ref<number>(300)
const items = ref<number>(300000)
const refWrap = ref<any>(null)
const scrollTop = ref<number>(0)
const startIndex = ref<number>(0)
const endIndex = ref<number>(0)
// 显示的条数
const visibleCount = computed<number>(() => {
return Math.ceil(wrapHeight.value / 30)
})
const listComputed = computed(()=>{
return list.slice(startIndex.value,Math.min(endIndex.value,list.length))
})
const scrollWrap = (e: any) => {
scrollTop.value = e.srcElement.scrollTop
showVisible(scrollTop)
}
const showVisible = (scrollTop:Ref):void=>{
// 当前数据显示的索引
startIndex.value = Math.floor(scrollTop.value / 30)
endIndex.value = startIndex.value + visibleCount.value + 2
}
onMounted(() => {
for (let i = 0; i < items.value; i++) {
list.push({
text: 'list_' + (i+1),
height: 30,
top: (30 * i).toString(),
})
}
showVisible(scrollTop)
console.log('mounted')
})
onActivated(()=>{
if(scrollTop.value!==0){
showVisible(scrollTop)
refWrap.value.scrollTop = scrollTop.value
}
})
return {
list,
items,
refWrap,
scrollWrap,
wrapHeight,
endIndex,
startIndex,
listComputed
}
},
})
</script>
<style scoped lang="scss">
.wrap {
overflow: auto;
position: relative;
.list {
position: absolute;
width: 100%;
}
}
</style>
讲解一下原理:
因为加载30w条数据,肯定一次性加载出来是会页面卡死的,那么就需要一次性只加载一部分,这个时候需要定好盒子的高度,并且定好内部展示列表的高度,css绝对定位去定位内容list的位置,通过js去计算每个item应该展示的位置,去获取滚动条滚动的距离,然后去计算顶部此时应该展示哪些数据,数据层分为一个渲染数据,一个原始数据,动态计算此时需要展示的数据索引,然后对原始数据进行截取
list.slice(startIndex.value,Math.min(endIndex.value,list.length))
展示效果
类似的,比如树形数据,按照这个思路,也可以做到加载大数据树,大数据树的后面再写
PS:自己改造改造vue2也能用