1. 有高度
1.1 vue-infinite-loading(vue2)
<infinite-loading
slot="append"
:identifier="identifier"
@infinite="loadManageTable"
force-use-infinite-wrapper=".el-table__body-wrapper"
>
<span slot="no-more"></span>
</infinite-loading>
import InfiniteLoading from 'vue-infinite-loading'
identifier: new Date(),
loadManageTable($state) {
setTimeout(() => {
if (this.list.length && this.list.length >= this.listInit.length) {
$state.complete()
return
}
this.list.push(
...this.listInit.slice(
this.list.length,
this.list.length + this.loadingPageSize
)
)
this.list.length && $state.loaded()
}, 500)
},
deactivated() {
this.identifier = new Date()
},
destroyed() {
this.identifier = null
}
具体查看
2. 剖析原理
<template>
<div class="vitual-list-wrap" ref="listWrapRef">
<div class="content" :style="contentStyle">
<div class="item" v-for="(item, index) in viewData.list" :key="index" :style="item.style">
{{ item.content }}
</div>
</div>
</div>
</template>
<script setup>
import { createApp, reactive, toRefs, computed, onMounted, ref } from 'vue'
const listWrapRef = ref(null)
const viewData = reactive({
list: [],
total: 1000,
height: 600,
rowHeight: 60,
startIndex: 0,
endIndex: 0,
timer: false,
bufferSize: 5
})
const contentStyle = computed(() => {
return {
height: `${viewData.total * viewData.rowHeight}px`,
position: 'relative'
}
})
const renderData = () => {
viewData.list = []
const { rowHeight, height, startIndex, total, bufferSize } = viewData
const limit = Math.ceil(height / rowHeight)
console.log(limit, '=limit')
viewData.endIndex = Math.min(startIndex + limit + bufferSize, total - 1)
for (let i = startIndex; i < viewData.endIndex; i++) {
viewData.list.push({
content: i,
style: {
top: `${i * rowHeight}px`
}
})
}
}
const handleScroll = callback => {
listWrapRef.value &&
listWrapRef.value.addEventListener('scroll', e => {
if (viewData.timer) {
return
}
const { rowHeight, startIndex, bufferSize } = viewData
const { scrollTop } = e.target
console.log('scrollTop: ', scrollTop)
const currentIndex = Math.floor(scrollTop / rowHeight)
viewData.timer = true
console.log(startIndex, currentIndex)
setTimeout(() => {
viewData.timer = false
if (currentIndex !== startIndex) {
viewData.startIndex = Math.max(currentIndex - bufferSize, 0)
callback()
}
}, 500)
})
}
onMounted(() => {
renderData()
handleScroll(renderData)
})
</script>
<style scoped>
* {
padding: 0px;
margin: 0px;
}
#app {
width: 300px;
border: 1px solid#e5e5e5;
}
.vitual-list-wrap {
position: relative;
height: 800px;
overflow-y: auto;
background-color: #ccc;
}
.content {
position: relative;
}
.item {
height: 60px;
padding: 10px 5px;
border-bottom: 1px solid#111;
position: absolute;
left: 0;
right: 0;
line-height: 60px;
}
</style>