Recently, ticketing items have returned too much data at one time, my computer can still hold, but when I see the customer’s computer suddenly exploded… It’s not like we’re going to look at tabular data optimization again
1. Problem summary
- The back end returns too much data at once and renders directly causing performance lag
- The dom rendering of large amounts of data on a lesser computer tends to freeze
- How do you optimize lists when function throttling and anti-shaking optimizations basically don’t work
2. Virtual scroll icon
In fact, it is listening to the scroll event to continuously update the existing list of data, as shown in the following figure:
If you look at the console, the number of divs in the list doesn’t change, it just changes the data inside it.
Graphic implementation logic: can be understood as a virtual scroll is three outer box for Windows, an intermediary for the height of the whole data list box just do not render any data open height and the effect of rolling, the inner box rendering and display data and inner scroll box constantly replace data and simulated rolling effect;
3. Code implementation
Points vUE and native JS for implementation can be used directly copy
vue
<template>
<div :style="`height:${viewH}px; overflow-y:scroll`" @scroll="handleScroll" class="out">
<div :style="`height:${scrollH}px`" class="list">
<div class="item_box" :style="`transform:translateY(${offsetY}px)`">
<div class="item"
:style="`height: ${itemH}px`"
v-for="(item, index) of list"
:key="index">
{{ item }}
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "virtualList".props: {
data: Array.// List total data
viewH: Number.// External height
itemH: Number.// Single height
},
data() {
return {
scrollH: ' '.// The entire scrolling list height
list: [].// The data is displayed each time
showNum: ' '.offsetY: ' '.// Dynamic offset - the outer box is set to scroll
lastTime: ' ',}},mounted() {
// Initialize the calculation
this.scrollH = this.data.length * this.itemH;
// Calculate the visualization height can be loaded several lists at a time, set several more to prevent direct replacement during scrolling
this.showNum = Math.floor(this.viewH / this.itemH) + 4;
// Display several by default
this.list = this.data.slice(0.this.showNum);
this.lastTime = new Date().getTime();
},
methods: {
handleScroll(e) {
if (new Date().getTime() - this.lastTime > 10) {
let scrollTop = e.target.scrollTop; // The width of the scroll bar
// After each scroll, the scrollTop value gets an offset that is divisible by itemH
ScrllTop = 1220 1220% this.itemH = 20 offsetY = 1200
this.offsetY = scrollTop - (scrollTop % this.itemH);
console.log(scrollTop, scrollTop % this.itemH);
this.list = this.data.slice(
Math.floor(scrollTop / this.itemH), // Count how many entries are involved
Math.floor(scrollTop / this.itemH) + this.showNum
)
this.lastTime = new Date().getTime(); }}}}</script>
Copy the code
/ / class<! DOCTYPE html><html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#list {
border: 1px solid # 333333;;
overflow-y: scroll;
}
.listBox {
border: 1px solid #00B7FF;
}
</style>
</head>
<body>
<div id="list"></div>
</body>
<script>
/* * Configuration items: * el: hook * data: all list items * viewH: list height * itemH: height of each item * list: current display items * * * showNum: number of display items * * */
class List {
constructor(opt) {
this.el = opt.el;
this.data = opt.data;
this.viewH = opt.viewH;
this.itemH = opt.itemH;
this.totalH = this.data.length * this.itemH + 'px';
this.list = [];
this.offsetY = 0;
this.showNum = 0;
this.lastTime = new Date().getTime();
this.el.style.height = this.viewH + 'px';
}
init() {
this.composeDom();
this.initData();
this.bindEvent();
}
composeDom() {
// Create a DOM structure
let totalBox = document.createElement('div'),
listBox = document.createElement('div');
totalBox.className = 'totalBox';
totalBox.style.height = this.totalH;
listBox.className = 'listBox';
totalBox.append(listBox);
this.el.append(totalBox);
this.totalBox = totalBox;
this.listBox = listBox;
}
initData() {
// Initialize the list
this.showNum = Math.floor(this.viewH / this.itemH) + 4;
this.list = this.data.slice(0.this.showNum);
this.createByList(this.list);
}
createByList(list) {
this.listBox.innerText = ' ';
let fragment = document.createDocumentFragment();
for (let i = 0; i < this.showNum; i++) {
let div = document.createElement('div');
div.style.height = this.itemH + 'px';
div.innerText = list[i];
fragment.append(div);
}
this.listBox.append(fragment);
}
bindEvent() {
this.el.addEventListener('scroll'.this.handleScroll.bind(this), false);
}
handleScroll(e) {
if (new Date().getTime() - this.lastTime > 20) {
let scrollTop = e.target.scrollTop,
prevNum = Math.floor(scrollTop / this.itemH);
this.offsetY = scrollTop - (scrollTop % this.itemH);
this.list = this.data.slice(prevNum, prevNum + this.showNum);
this.createByList(this.list);
this.listBox.style.transform = `translateY(The ${this.offsetY}px)`
this.lastTime = new Date().getTime(); }}}let data = [];
for (let i = 0; i < 999; i++) {
data.push(i + 1);
}
// The instance is mounted
new List({
el: document.getElementById('list'),
data,
viewH: 600.itemH: 40
}).init();
</script>
</html>
Copy the code
4. Summarize the knowledge
It is the use of scrollTop, how to calculate how many pieces of data have been involved according to the height of involvement, to show the subsequent data. Well actually very simple, but also study an afternoon ah, now still working overtime, have nothing to do to write out the problems encountered today, I hope to help you. ヾ(◍°∇°◍) Blue