虚拟滚动 实现
javascript 性能优化 虚拟滚动 前端
<!DOCTYPE html>
<html>
<head>
<title>TestVirtualScroll</title>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="counter">
<div class="outer" @scroll="onScroll">
<ul :style="{height:totalHeight}">
<li
v-for="(item,index) in renderDisplayContent()"
:style="rowStyle(item.orderNum)"
>
row:{{item.data.name}}{{item.orderNum}}
</li>
</ul>
</div>
</div>
<script type="text/javascript">
const Counter = {
data() {
return {
counter: 0,
wrapperHeight: 800,
rowHeight: 40,
startIndex: 0,
endIndex: 0,
content: [],
};
},
computed: {
total() {
return this.content.length;
},
totalHeight() {
return this.total * this.rowHeight + "px";
},
limit() {
return Math.min(
this.total,
Math.ceil(this.wrapperHeight / this.rowHeight)
);
},
},
methods: {
onScroll(evt) {
const { scrollTop } = evt.target;
const { startIndex, total, rowHeight, limit } = this;
const currentStartIndex = Math.floor(scrollTop / rowHeight);
// 如果currentStartIndex 和 startIndex 不同(我们需要更新数据了)
if (currentStartIndex !== startIndex) {
this.startIndex = currentStartIndex;
this.endIndex = Math.min(currentStartIndex + limit, total - 1);
}
},
renderDisplayContent() {
if (this.content && this.content.length) {
const { rowHeight, startIndex, endIndex } = this;
const content = [];
// 用了 <= 是为了渲染x+1个元素用来在让滚动变得连续
for (let i = startIndex; i <= endIndex; ++i) {
content.push({ orderNum: i, data: this.content[i] || {} });
}
return content;
} else {
return [];
}
},
//每行数据使用绝对定位展示
rowStyle(index) {
return {
width: "100%",
height: this.rowHeight + "px",
lineHeight: this.rowHeight + "px",
position: "absolute",
left: 0,
right: 0,
top: index * this.rowHeight + "px",
borderBottom: "1px solid #000",
};
},
},
mounted() {
setTimeout(
function () {
this.content.length = 200000;
this.content.fill({ name: "Niko" });
this.endIndex = this.limit - 1;
}.bind(this),
500
);
//初始化时 endIndex赋值为最大展示条数
},
};
Vue.createApp(Counter).mount("#counter");
</script>
</body>
<style type="text/css">
.outer {
border: 1px solid;
height: 300px;
width: 200px;
overflow: auto;
}
.outer ul {
position: relative;
}
.outer li {
height: 20px;
line-height: 20px;
}
</style>
</html>