Recently made a demand, when a list of about 20,000 data did not allow to make page, if the page 20000 direct rendering data on some low-equipped computer may shine into pages stuck Based on this demand, we to a virtual handwriting list
Thinking
- Fixed display list only a small amount of data, such as 60
- Keep to insert deleted from the list when scrolling dom
- startIndex, endIndex, constantly changing this to get the latest display list
- paddingTop, paddingBottom distraction scroll area of the container
First look at when plugged directly into the list of 20000, the performance of the page
you can see the red flame figure has been part of, dom rendering is also time-consuming but also more than 1s
Then look at the performance of the page when using virtual list
can be seen from the figure flame, a green flame figure, which proves to be rendered by a list of the virtual page performance has been greatly improved
Simple demo implement virtual list
We assume there is a container, 600px height, 30px height of each list item, then we can calculate the total height of the roll container according to the length of the list may also know the height of the display 60 data, at this time we can give the container plus a paddingBottom, to distraction container to simulate the height of the page should scroll
this.paddingBottom = this.allHeight - this.scrollList.length * 30
Container also need paddingTop used when the container is removed after rolling the top of the data hold up scrollTop
Finally, we need to scroll event listener container to constant changes paddingTop, paddingBottom, startIndex, endIndex
final effect
Finally, attach all of the code
<!doctype html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.container {
width: 300px;
height: 600px;
overflow: auto;
border: 1px solid;
margin: 100px auto;
}
.item {
height: 29px;
line-height: 30px;
border-bottom: 1px solid #aaa;
padding-left: 20px;
}
</style>
</head>
<body>
<div id="app">
<button @click="add">增加</button>
<div class="container" ref="container">
<div class="scroll-wrapper" :style="style">
<div v-for="(item, index) in scrollList" :key="index" class="item">{{item}}</div>
</div>
</div>
</div>
<script src="./vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
list: [
'测试数据'
],
startIndex: 0,
endIndex: 60,
paddingTop: 0,
paddingBottom: 0,
allHeight: 0
},
computed: {
scrollList() {
return this.list.slice(this.startIndex, this.endIndex)
},
style() {
return {
paddingTop: this.paddingTop + 'px',
paddingBottom: this.paddingBottom + 'px'
}
}
},
watch: {
list(val) {
const valLen = val.length
this.allHeight = valLen * 30
this.paddingBottom = this.allHeight - this.scrollList.length * 30
}
},
mounted() {
const container = this.$refs.container
container.addEventListener('scroll', () => {
const top = container.scrollTop
this.startIndex = Math.floor(top / 30)
this.endIndex = this.startIndex + 60
this.paddingTop = top
if (this.endIndex >= this.list.length - 1) {
this.paddingBottom = 0
return
}
this.paddingBottom = this.allHeight - 600 - top
})
},
methods: {
add() {
let arr = new Array(50000).fill(0)
arr = arr.map((item, index) => {
return index
})
this.list = [
...this.list,
...arr
]
}
}
})
</script>
</body>
</html>