虚拟滚动实现
废话少说,先上代码,再聊原理
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>虚拟滚动实现</title>
<script src="vue.js"></script>
<style>
* {
padding: 0;
margin: 0;
}
.view-container {
overflow: hidden;
padding: 5px;
margin: 5px;
border: 1px solid #ccc;
}
.list-scroll-wrapper {
height: 100%;
overflow: auto;
}
.row-wrapper {
height: 30px;
line-height: 30px;
}
.virtual-container {
position: relative;
}
</style>
</head>
<body>
<div id="app">
<div class="view-container" :style="{height: viewHeight + 'px'}"> <!-- 最外层的可视 -->
<div class="list-scroll-wrapper" @scroll="handleScroll"> <!-- 滚动层 -->
<div class="virtual-container" :style="{height: virtualHeight + 'px'}"> <!-- 虚拟高度层 -->
<div style="position: absolute; left: 0;" :style="{top: viewTop + 'px'}"> <!-- 绝对定位,显示数据,否则会随着滚动而滚动 -->
<p v-for="item in list" :key="item.id" class="row-wrapper"> {{item.val}}</p> <!-- 实际显示的表格 -->
</div>
</div>
</div>
</div>
</div>
<script>
// 目标:加载10W行数据
// 实现:采用虚拟滚动技术
// 1.创建显示的列表
// 2.控制显示的高度
// 3.根据数据虚拟出一个高度
// 4.虚拟的高度外包一层,用于实现滚动
// 5.实际的显示列表采用绝对定位,实时改变top,保证一直可视
new Vue({
el: '#app',
data: {
data: [], // 所有数据
list: [], // 当前显示的可视数据
rowHeight: 30, // 行高
viewHeight: 300, // 可视列表高度
virtualHeight: 300, // 虚拟的高度,
viewTop: 0,
},
created() {
this.mockData()
this.refreshList()
},
mounted() {
this.virtualHeight = this.data.length * this.rowHeight
},
methods: {
mockData() { // 造数据
const data = []
for(let i=0; i<100000; i++) {
data.push({
id: i,
val: 'data-' + i
})
}
this.data = data
},
refreshList(start = 0, end = 20) { // 根据传入的值去渲染数据
const list = []
end = end < this.data.length ? end : this.data.length
for(let i=start; i<end; i++) {
list.push(this.data[i])
}
this.list = list
},
handleScroll(e) {
const scrollTop = e.target.scrollTop
this.viewTop = scrollTop
// 根据滚动位置进行计算显示的数据
const start = parseInt(scrollTop / this.rowHeight) + 1
this.refreshList(start, start + 20)
}
}
})
</script>
</body>
</html>
理论研究
简单来说就是通过实际的数据量,然后根据数据来虚拟出一个虚拟高度
然后通过监测这个虚拟高度的滚动高度来动态设置显示的数据
由于显示的数据都在内存,页面渲染的元素只有可视区域的元素,所以理论上来讲能显示多少数据取决于客户端的内存
不过由于是一值滚动的,所以需要固定可视的列表,否则会随着滚动而滚动
固定显示列表可以采用绝对定位,不过这样外面就需要设置一个相对定位
也可以用采用css3的transformY去实现
最后,具体可以查看源码
这里只作技术攻关实现,更多细节请自行实现吧