一、虚拟滚动列表
虚拟列表的意思就是在数据量超大的情况下,页面只渲染可视范围的列表,减少dom数量,控制页面性能的效果。
二、具体实现
talk is cheap, show me the code.
<template>
<div class="virtual-list">
<h1>虚拟列表</h1>
<div class="list-view" ref="scrollBox" @scroll="handleScroll">
<div
class="list-view-phantom"
:style="{
height: contentHeight
}"
>
<div ref="content" class="list-view-content">
<div
class="list-view-item"
:style="{
height: itemHeight + 'px'
}"
v-for="item in visibleData"
:key="item"
@click="itemClick(item)"
>
{{ item }}
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
datalist: [],
itemHeight: 30,
visibleData: []
};
},
mounted() {
// 创建一个贼大的数据数组
for (let i = 0; i < 10000; i++) {
this.datalist.push(i);
}
this.updateVisibleData();
},
computed: {
contentHeight() {
return this.datalist.length * this.itemHeight + "px";
}
},
methods: {
scrollview() {
const scrollTop = this.$refs.container.scrollTop;
console.log(scrollTop);
},
updateVisibleData(scrollTop = 0) {
// 计算能显示多少个
const visibleCount = Math.ceil(
this.$refs.scrollBox.clientHeight / this.itemHeight
);
// 计算可视区域第一个的数组下标
const start = Math.floor(scrollTop / this.itemHeight);
// 计算可视区域最后一个的数组下标
const end = start + visibleCount;
// 截取可视数组
this.visibleData = this.datalist.slice(start, end);
// 设置窗口偏移的量 可视窗口的第一个*item的高度
this.$refs.content.style.webkitTransform = `translate3d(0, ${start *
this.itemHeight}px, 0)`;
},
handleScroll() {
// 优化方向,可以节流一下
const scrollTop = this.$refs.scrollBox.scrollTop;
this.updateVisibleData(scrollTop);
},
itemClick(item) {
console.log(item);
}
}
};
</script>
<style lang="less" scoped>
.viewport {
width: 300px;
height: 400px;
overflow: auto;
.container {
height: 6000px;
.item {
width: 100%;
height: 50px;
border: solid 1px red;
}
}
}
.list-view {
height: 400px;
overflow: auto;
position: relative;
border: 1px solid #aaa;
}
.list-view-phantom {
position: absolute;
left: 0;
top: 0;
right: 0;
z-index: -1;
}
.list-view-content {
left: 0;
right: 0;
top: 0;
position: absolute;
}
.list-view-item {
padding: 5px;
color: #666;
line-height: 30px;
box-sizing: border-box;
z-index: 1;
cursor: pointer;
}
</style>