长列表优化
由于长列表的特殊性,即使前面的列表用户不看了,前面dom也需要一直存在,优化为只要在视图窗口就可以。
js代码:
<template>
<div id="u" :style="{padding:padding}">
<slot :sliceitems="sliceitems"></slot>
</div>
</template>
<script>
export default {
props:{
items:{
require:true
},
itemsHeight:{
require:true
}
},
data() {
return {
buffer:2,
scrollTop:0,
viewHeight:0,
}
},
computed:{
over(){
return Math.max(this.scrollTop/this.itemsHeight-this.buffer,0)
},
down(){
return Math.ceil(
(this.scrollTop+this.viewHeight)/this.itemsHeight+this.buffer,this.items.length
)
},
sliceitems(){
return this.items.slice(this.over,this.down)
},
padding(){
return `${this.over*this.itemsHeight}px 0 ${(this.items.length-this.down)*this.itemsHeight}px 0`
}
},
created() {
document.addEventListener("scroll",this.onScroll,{
passive:true
})
this.scrollTop=window.scrollY
this.viewHeight=window.innerHeight
},
destroyed(){
document.removeEventListener("scroll",this.onScroll)
},
methods: {
onScroll: function(){
this.scrollTop=window.scrollY
this.viewHeight=window.innerHeight
}
},
}
</script>
</script>
其中over是已经滚动过的节点,down表示当前视口滚动到的节点,为了用户体验我们会多出一个buffer值,上下会多5个元素渲染,并且我们需要定义一个最大值和最小值。
passive:true是直接执行浏览器的默认事件,而不会等onScroll。
最重要的就是padding值,让此时视图一直居中,所以要动态的变化。
vue页面如下:
<template>
<div >
<u-infinite-list :items="items" :itemsHeight="80" #default="{ sliceitems }">
<ul>
<li class="items" v-for="item in sliceitems" :key="item">{{item}}</li>
</ul>
</u-infinite-list>
</div>
</template>
<script>
import UInfiniteList from '../components/UInfiniteList.vue'
export default {
name: 'Home',
data() {
return {
items:[]
}
},
created() {
for (let index = 0; index < 200; index++) {
this.items.push(index)
}
},
components:{
UInfiniteList
}
}
</script>
<style >
.items{
height: 80px;
line-height: 80px;
list-style: none;
}
</style>
演示如下:
可以看到dom前面和后面都没有,只有视图窗口才有。