虚拟列表实现思路
设置一个容器,用来计算可视区域大小
设置一个大容器,用来承载所有数据的高度和生成外部滚动条
设置一个展示数据的区域
设置开始展示数据的坐标,和结束展示数据的坐标,根据scrollTop计算出每次滑动后下次展示数据的开始坐标,根据scrollTop+可视区域大小计算出化冻后下次展示数据的结束坐标
编码使用vue3+element-plus,环境搭建,参考koa官网和element-plus官网
页面展示部分
<template>
<h3>虚拟表格</h3>
<!--容器部分-->
<div class="table-container">
<!--固定表头-->
<table class="table-head" border>
<thead>
<tr>
<th>Date</th>
<th>Name</th>
<th>Address</th>
</tr>
shixi
</thead>
</table>
<!--滚动区域-->
<div class="table-body" @scroll="handleScroll">
<!--不可见区域,用来撑起滚动区域高度-->
<table border class="scroll-table" height="100%">
<tbody>
<tr v-for="(item, index) in tableData" :key="index">
<td>{{ item.date }}</td>
<td>{{ item.name }}</td>
<td>{{ item.address }}</td>
</tr>
<div class="bar"></div>
</tbody>
</table>
<!--可视区域-->
<table border class="scroll-table-show" height="100%">
<tbody>
<tr v-for="(item, index) in virtalTable" :key="index">
<td>{{ item.date }}</td>
<td>{{ item.name }}</td>
<td>{{ item.address }}</td>
</tr>
<div class="bar"></div>
</tbody>
</table>
</div>
</div>
</template>
<style lang="scss">
html,
body {
height: 500px;
}
.table-container {
height: 500px;
display: flex;
flex-direction: column;
overflow: hidden;
.table-head {
background-color: #e1f3d8;
}
.table-body {
position: relative;
flex: 1;
background-color: #faecd8;
overflow-y: auto;
}
.scroll-table {
visibility: hidden;
}
.scroll-table-show {
position: absolute;
left: 0;
right: 0;
}
}
table {
td,
th {
padding: 8px 0;
border-color: #dcdfe6;
border-width: 1px solid;
}
td:nth-child(2),
th:nth-child(2),
td:nth-child(1),
th:nth-child(1) {
width: 200px;
}
border-collapse: collapse;
width: 100%;
}
</style>
js部分
<script lang="ts" setup>
import { table } from "console"
import { tr } from "element-plus/es/locale"
import { ref, onMounted, computed } from "vue"
//容器高度
let containerHeight = ref<number>(0)
//滑动高度
let scrollHeight = ref<number>(0)
//全部数据
let tableData = ref<Person[]>([])
//展示虚拟数据
let virtalTable = ref<Person[]>([])
//tr高度
let trHeight = ref<number>(0)
//可以容纳多少条数据
let showNum = computed(() => {
return Math.ceil(containerHeight.value / trHeight.value)
})
//展示数据的开始下标
let start = ref<Number>(0)
//每次展示10条数据,展示数据的结束下标
let end = ref<Number>(10)
let top = ref<number>(0)
onMounted(() => {
const ele = document.querySelector(".table-body")
containerHeight.value = ele.offsetHeight
const tr = document.querySelector("tr")
trHeight.value = tr.offsetHeight
const table = document.querySelector("tbody")
scrollHeight.value = table.offsetHeight
console.log(
containerHeight.value,
trHeight.value,
showNum.value,
scrollHeight.value
)
//初始化加载函数
renderData(start.value, end.value, tableData.value)
})
interface Person {
date: string
name: string
address: string
}
//用来动态生成数据
generateTableData()
function generateTableData() {
let data = []
for (let index = 0; index < 2000; index++) {
data.push({
date: "2016-05-03",
name: "Tom" + index,
address: "No. 189, Grove St, Los Angeles",
})
}
tableData.value = data
}
//处理滚动事件
function handleScroll(evt) {
//获取滑动距离
const scrollTop = document.querySelector(".table-body").scrollTop
start.value = Math.ceil(scrollTop / trHeight.value)
end.value = Math.ceil((scrollTop + containerHeight.value) / trHeight.value)
// top.value = screenTop
//将可视表格,的top改为滑动距离,或者不设置position,设置padding-top也是可以的
document.querySelector(".scroll-table-show ").style.top = scrollTop + "px"
renderData(start.value, end.value, tableData.value)
}
//加载表格数据
function renderData(start: number, end: number, tableData: Person[]) {
virtalTable.value = tableData.slice(start, end)
console.log(virtalTable.value)
}
</script>











网友评论