开篇
通过 vue 进行列表展示的时候如果数据太多可能会卡顿,这里通过滑动计算只创建跟刷新可见部分 dom 元素,这里仅仅代表着复用思路
一、效果展示
两列均为局部可视范围内数据刷新
二、代码
实现的主要思路:
1、提前保留可视div的高度,计算出可视高度能填满情况下最少的单元格条数;
2、根据提供的每个单元格高度和总数据条数计算出总的可滑动div高度,使其可以滑动;
3、在上述可滑动div内部再包裹一层div,此节点的作用就是在滑动过程中,改变自身的 top 值,使之在父节点滑动中始终出现在父节点的可视区域内。
4、根据滑动的距离更新vue数据,但是也只是更新能填满可视区域最小条数。
<div class="main">
<div v-for="(dom) in longListEl" :key="dom.id" class="longList">
<div :id="dom.id" class="contain">
<div style="width: calc(100% - 20px);position: relative;">
<div :style="{height:`${expectationCellHeight}px`}" v-for="(item,index) in dom.data" :key="item.id">
{{ item.title }}
</div>
</div>
</div>
</div>
</div>
export default {
data() {
return {
longListData:[],
expectationCellHeight:40,
longListEl:[{id:'contain',data:[]},{id:'contain1',data:[]}],
longListDataManages:[]
};
},
mounted() {
for(let index = 0;index < 250000;index ++){
this.longListData.push({id:index,title:('我是第' + index + '个')})
}
this.$nextTick(()=>{
this.longListEl.forEach((dom)=>{
let containEl = document.getElementById(dom.id)
if(containEl){
this.longListDataManages.push(new LongListDataManage(containEl,this.longListData,this.expectationCellHeight,(data)=>{
dom.data = data
}))
}
})
})
},
methods: {
},
};
function LongListDataManage(el,totalData,expectationCellHeight,refreshDataCallBack){
this.el = el//需要操作的dom
this.startIndex = 0//数据源的开始索引
this.endIndex = 0//数据源的结束索引
this.containElHeight = el ? el.offsetHeight : 0//可视区域高度
this.totalData = totalData//全部数据源
this.refreshDataCallBack = refreshDataCallBack//数据刷新回调
this.expectationCellHeight = expectationCellHeight//预期的单元cell高度
this.expectationCellFullScreenNum = 0//预期可视区域展示的单元条数
this.expectationTotalHeight = 0//预期滑动的最大高度
this.scrollTop = 0//当前滚动距离
this.beginRefreshDataDistance = expectationCellHeight//滑动触发刷新数据最小距离,这里仅为一个单元格高度
// 开始填充数据
this.begin = function(){
this.initData()
this.getCurrentShowDatas()
this.addListenerScroll()
}
// 初始化参数
this.initData = function(){
//总高度设定
this.expectationTotalHeight = this.totalData.length * this.expectationCellHeight
this.el.style.height = this.expectationTotalHeight + 'px'
//数据源的结束索引设定(向上取整)
this.endIndex = this.expectationCellFullScreenNum = Math.ceil((this.containElHeight / this.expectationCellHeight) + 0.1)
}
// 开始获取当前需要展示的区间
this.getCurrentShowDatas = function(){
//截取数据源开始跟结束节点之间的数据
let currentData = this.totalData.slice(this.startIndex,this.endIndex)
//给vue提供数据
this.refreshDataCallBack(currentData)
}
// 监听滚动
this.addListenerScroll = function(){
//父节点
let parentNode = this.el.parentNode
//第一个子节点(改变其top值实现始终在父节点的可视区域内)
let firstChild = this.el.firstChild
let scrollingEvent = ()=>{
let scrollTop = parentNode.scrollTop
//滑动的距离超过规定的阀值或者滑动距离为0进行数据源重置
if(Math.abs(scrollTop - this.scrollTop) >= this.beginRefreshDataDistance || scrollTop <= 0){
//更改数据源区间索引
this.startIndex = Math.ceil(scrollTop / this.expectationCellHeight)
this.endIndex = this.startIndex + this.expectationCellFullScreenNum
//上下平移可视区域展示dom,实现屏幕相对位置不变
firstChild.style.top = scrollTop + 'px'
//回传数据源
this.getCurrentShowDatas()
this.scrollTop = scrollTop
}
}
//开始监听滚动
parentNode.addEventListener("scroll", scrollingEvent)
}
}
复用其实是由vue来处理的,这里仅是将刷新数据进行了筛选以达到刷新最小数据条数的目的,这里仅仅是简单的实现思路,希望对大家有帮助,更多关于vue 长列表数据刷新的资料请关注编程网其它相关文章!