js优化中的虚拟列表
文章类型:Javascript
发布者:admin
发布时间:2023-05-19
在操作大量数据时,一次性渲染到页面会导致卡顿,不流畅,需要进行优化
1:虚拟化渲染和虚拟列表是在处理大量数据时常用的性能优化技术。虚拟化渲染是一种通用的概念,用于指代只渲染可见区域内容的技术,而虚拟列表是一种具体的实现方式,用于处理长列表的优化
1:第一步:确定视口宽高,也就是确定用户可视区域以及显示多少个,每个行高
2:第二步:计算出滚动条内容高度,通过总长度*每个行高
3:第三步:进行计算属性截取,固定显示设置的个数,冻结对象有利于避免绑定依赖关系
4:第四步:进行绑定滚动事件,计算滚动的位置/每个行高得出滚动的个数,调整起始位置和结束位置
5:第五步:进行滚动位置的平移拉回,往上卷了多少距离,数据变化后像下拉回多少距离
//v3版本
<script setup lang="ts">
//虚拟列表
import {ref, reactive, onMounted,computed} from 'vue'
//定义大数据源 并且进行对象的冻结,避免vue依赖监听
const list=reactive(Object.freeze(new Array(200000).fill(null).map((item,i)=>({n:i+1}))))
//定义获取操作dom的ref
const viewport=ref<any>(null)
const scrollBar=ref<any>(null)
const showbox=ref<any>(null)
//定义显示的个数以及每个的高度
const viewCount=ref(20)
const rowHeight=ref(30)
//定义起始位置和结束位置
const start=ref(0)
const end=ref(20)
onMounted(()=>{
//计算出总高度和当前显示区域视口高度
viewport.value.style.height=viewCount.value*rowHeight.value+'px'
scrollBar.value.style.height=list.length*rowHeight.value+'px'
})
//滚动事件 进行更换数据值,起始位置
const scrollShow=()=>{
let scrollTop=viewport.value.scrollTop
console.log(scrollTop)
start.value=Math.round(scrollTop/rowHeight.value)
end.value=start.value+viewCount.value
//向上卷多少个,往下拉多少距离
showbox.value.style.transform=`translateY(${scrollTop}px)`
}
//计算要显示出的个数
const showList=computed(()=>(list.slice(start.value,end.value)))
</script>
<template>
<div>
<div class="box" ref="viewport" :style="{'--rowHeight':rowHeight+'px'}" @scroll="scrollShow">
<div class="scrollbox" ref="scrollBar"></div>
<div class="rowbox" ref="showbox">
<p class="row" v-for="(item,index) in showList" :key="item.n">{{item.n}}</p>
</div>
</div>
</div>
</template>
<style lang="less" scoped>
.box{
width: 400px;
height: 500px;
position: fixed;
left: 0;
top: 0;
bottom: 0;
right: 0;
margin: auto;
overflow-y: scroll;
background: gainsboro;
}
p{
margin: 0;
}
.rowbox{
position: absolute;
left: 0;
top: 0;
}
.row{
height: var(--rowHeight);
}
</style>//v2版本
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style>
.box{
width: 300px;
height: 400px;
position: fixed;
margin: auto;
overflow-y: scroll;
left: 0;
right: 0;
bottom: 0;
top: 0;
background: gainsboro;
}
.scroller{
/* height: 3000px; */
}
.list{
position: absolute;
left: 0;
top: 0;
}
.row{
margin: 0 ;
height: var(--rowheight);
}
</style>
</head>
<body>
<div id="app">
<div class="box" ref="viewport" :style="{'--rowheight':rowHeight+'px'}" @scroll="onScroll">
<div class="scroller" ref="scrollbar"></div>
<div class="list" ref="list">
<p class="row" v-for="(item,index) in showList" >{{item.n}}</p>
</div>
</div>
</div>
</body>
</html>
<script src="js/vue.js"></script>
<script>
const bigList=new Array(10000).fill(null).map((item,i)=>({n:i+1}))
new Vue({
el:'#app',
computed:{
showList(){
return this.list.slice(this.start,this.end)
}
},
data(){
return{
list:Object.freeze(bigList),
viewCount:20,
rowHeight:30,
start:0,
end:20
}
},
methods:{
onScroll(){
let offsettop=this.$refs.viewport.scrollTop
console.log(offsettop)
this.start=Math.round(offsettop/this.rowHeight)
this.end=this.start+this.viewCount
this.$refs.list.style.transform=`translateY(${offsettop}px)`
}
},
mounted(){
this.$refs.viewport.style.height=this.rowHeight*this.viewCount+'px'
this.$refs.scrollbar.style.height=this.rowHeight*this.list.length+'px'
}
})
</script>
暂无评论,快来发表第一条评论吧~