功能说明:每次加载10条数据,数据量限制在 30条;
- 包版本:
- "element-ui": "^2.15.12",
- "vue": "^2.6.14",
- 文件说明,
- banks.js,数据文件
- dataLoader.js 数据加载器,核心功能
- elSelectMassData.vue,组件
1. banks.js,数据文件
const MaxLen = 100;
var banks = [];
for(let i=0;i<MaxLen;i++){
banks.push({
text:"银行"+(i+1),
value:"id-"+i
})
}
export default banks;
2. dataLoader.js,加载器
- 文件,dataLoader.js 数据加载器,核心功能
- getNext(),获取下一片数据,只是在初始化使用一下
- getLast(),获取上一片数据,不向外暴露
const STATUS = {
Top:'top',
Bottom:'bottom',
}
class DataLoader {
constructor(){
this.data = []; //数据
this.len = 0; //数据长度;
this.indexStart = 0; //开始游标;
this.indexEnd = 0; //结束游标;
this.result = []; //结果集;
this.resultSize = 30; //结果集所能存储的容量大小;
//(这个没用,后面有时间可以优化,因为是引用类型所以不用也可以生效)
this.callback = null; //回调函数;
this.ele = null; //容器元素;
this.status = STATUS.Top; // top | bottom ; 顶部,底部; STATUS
this.config = {
total:100, //每次加载条数
// isLog:true, //是否打印日志
}
}
init(data,config={}){
this.updateData(data);
this.updateConfig(config)
if(!this.ele){
throw new Error('请设置容器元素');
}
}
updateData(data){
this.data = JSON.parse(JSON.stringify(data));
this.len = this.data.length;
}
updateConfig(config){
Object.keys(config).forEach((key)=>{
if(key != 'ele'){
this.config[key] = config[key]
}
})
if(config.ele){
this.removeOnScroll();
this.ele = config.ele;
this.addOnScrollEvent();
}
}
addOnScrollEvent(){
console.log(this);
this.ele.addEventListener('scroll',this.onScroll.bind(null,this));
}
removeOnScroll(){
this?.ele &&
this.ele.removeEventListener('scroll',this.onScroll.bind(null,this));
}
onScroll(that,e){
const { scrollHeight, scrollTop, clientHeight} = e.target;
// 滚动到顶部
if(scrollTop <= 0){
console.log('--top');
that.getLast();
}
// 滚动到底部(上取整的目的是,有一个盒子问题, win缩放比)
else if(scrollHeight - Math.ceil(scrollTop) <= clientHeight){
console.log('--bottom');
that.getNext();
}
}
getNext(){
// 已经到达底部(在下面设定)
if(this.status == STATUS.Bottom){
console.warn('已经到达了底部');
return
}
if(this.status == STATUS.Top) this.status = null;
let data = [];
const startIndex = this.indexEnd;
this.indexEnd = this.indexEnd + this.config.total;
//如果游标小于 数据长度
if(this.indexEnd < this.len){
data = this.data.slice(startIndex,this.indexEnd)
//否则,游标大于数据长度
}else{
data = this.data.slice(startIndex);
this.indexEnd = this.len;
this.status = STATUS.Bottom
}
this.result.push(...data);
if(this.result.length > this.resultSize){
const delArr = this.result.splice(0,this.result.length-this.resultSize);
if(delArr.length){
this.indexStart += delArr.length;
console.log('++[indexStart]:',delArr.length, this.indexStart);
}
const { scrollHeight, clientHeight} = this.ele;
setTimeout(()=>{
//30个元素,每个元素的高度;
const size = scrollHeight/this.resultSize;
//在可视区域里面,有多个元素可存在,上去整;
const clientEleCount = Math.ceil(clientHeight/size);
// 减去 增加的10个,减去可视区域的10个;计算出剩余的top;
const count = this.resultSize - (this.config.total) - clientEleCount;
//最终结果,再进行偏移量处理;
this.ele.scrollTop = parseInt(count * size + 18)
},0)
}
return {
status:this.status,
data:this.result
}
}
getLast(){
// 已经到达顶部
if(this.status == STATUS.Top){
console.warn('已经到达了顶部')
return;
}
if(this.status == STATUS.Bottom) this.status = null;
let data = [];
let startIndex = this.indexStart - this.config.total; // test 11 | 2, | 0 , 10
//设置禁止
if(startIndex < 1){
this.status = STATUS.Top;
if(this.indexStart < 0) this.indexStart = 0;
if(this.indexStart == 0 ) return;
data = this.data.slice(0,this.indexStart);
this.indexStart = 0;
}else{
data = this.data.slice(startIndex,this.indexStart);
this.indexStart = startIndex;
}
this.result.unshift(...data);
if(this.result.length > this.resultSize){
const delArr = this.result.splice(this.resultSize);
if(delArr.length){
this.indexEnd -= delArr.length;
console.log('--[indexEnd]: ',delArr.length, this.indexStart, this.indexEnd);
}
const { scrollHeight } = this.ele;
setTimeout(() => {
const size = scrollHeight/this.resultSize;
this.ele.scrollTop = parseInt(size * (this.config.total) )
}, 0);
}
return {
status:this.status,
data:this.result
}
}
}
export default new DataLoader();
3. elSelectMassData.vue,组件
<template>
<div>
<h2>el-select大量数据优化</h2>
<el-select
v-model="value"
placeholder="请选择">
<el-option
v-for="item in list"
:key="item.value"
:label="item.text"
:value="item.value">
</el-option>
</el-select>
</div>
</template>
<script>
import banks from '@/data/banks.js'; //数据源
import dataLoader from '@/utils/dataLoader'; //加载器
export default {
cname:"ElSelect大量数据优化",
data(){
return{
list: [],
value: ''
}},
mounted(){
const ele = document.querySelector(".el-select-dropdown__wrap.el-scrollbar__wrap");
if(ele){
dataLoader.init(banks,{
ele,
total:10,
resultSize:30,
callback:this.getData
});
}
const {data} = dataLoader.getNext();
this.list = data;
},
methods:{
getData(res){
this.list = {...res.data};
},
},
}
</script>
the End。