解決el-select數(shù)據(jù)量過大的3種方案
背景
最近做完一個小的后臺管理系統(tǒng),快上線了,發(fā)現(xiàn)一個問題,有2個select的選項框線上的數(shù)據(jù)量是1w+。。而測試環(huán)境都是幾百的,所以導(dǎo)致頁面直接卡住了,over了。

想了一下,如果接口支持搜索和分頁,那直接通過上拉加載就可以了。但后端不太愿意改??。行吧,前端搞也是可以的。
方案
通過一頓搜索加聯(lián)想總結(jié)了3種方法,以下方法都需要支持開啟filterable支持搜索。
| 標(biāo)題 | 具體 | 問題 |
|---|---|---|
| 方案1 | 只展示前100條數(shù)據(jù),這個的話配合filter-method每次只返回前100條數(shù)據(jù)。 | 限制展示的條數(shù)可能不全,搜索需要多搜索點內(nèi)容 |
| 方案2 | 分頁方式,通過指令實現(xiàn)上拉加載,不斷上拉數(shù)據(jù)展示數(shù)據(jù)。 | 僅過濾加載出來的數(shù)據(jù),需要配合filterMethod過濾數(shù)據(jù) |
| 方案3 | options列表采用虛擬列表實現(xiàn)。 | 成本高,需要引入虛擬列表組件或者自己手寫 |
方案一,青銅段位 filterMethod直接過濾數(shù)據(jù)量
<template>
<el-select
v-model="value"
clearable filterable
:filter-method="filterMethod">
<el-option
v-for="(item, index) in options.slice(0, 100)"
:key="index"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</template>
export default {
name: 'Demo',
data() {
return {
options: [],
value: ''
}
},
beforeMount() {
this.getList();
},
methods: {
// 模擬獲取大量數(shù)據(jù)
getList() {
for (let i = 0; i < 25000; i++) {
this.options.push({label: "選擇"+i,value:"選擇"+i});
}
},
filterMethod(val) {
console.log('filterMethod', val);
this.options = this.options.filter(item => item.value.indexOf(val) > -1).slice(0, 100);
},
visibleChange() {
console.log('visibleChange');
}
}
}方案二、 白銀段位 自定義滾動指令,實現(xiàn)翻頁加載
寫自定義滾動指令,options列表滾動到底部后,再加載下一頁。但這時候篩選出來的是已經(jīng)滾動出來的值。
這里如果直接使用filterable來搜索,搜索出來的內(nèi)容是已經(jīng)滑動出來的內(nèi)容。如果想篩選全部的,就需要重寫filterMethod方法來自定義過濾功能??梢愿鶕?jù)情況選擇是否要重寫filterMethod。

<template>
<div class="dashboard-editor-container">
<el-select
v-model="value"
clearable
filterable
v-el-select-loadmore="loadMore"
:filter-method="filterMethod">
<el-option
v-for="(item, index) in options"
:key="index"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</div>
</template>
<script>
export default {
name: 'Demo',
data() {
return {
options: [],
value: '',
pageNo: 0
}
},
beforeMount() {
this.getList();
},
methods: {
// 模擬獲取大量數(shù)據(jù)
getList() {
const data = [];
for (let i = 0; i < 25000; i++) {
data.push({label: "選擇"+i,value:"選擇"+i});
}
this.allData = data;
this.data = data;
this.getPageList()
},
getPageList(pageSize = 10) {
this.pageNo++;
const list = this.data.slice(0, pageSize * (this.pageNo));
this.options = list;
},
loadMore() {
this.getPageList();
},
filterMethod(val) {
this.data = val ? this.allData.filter(item => item.label.indexOf(val) > -1) : this.allData;
this.getPageList();
}
},
directives:{
'el-select-loadmore':(el, binding) => {
// 獲取element-ui定義好的scroll父元素
const wrapEl = el.querySelector(".el-select-dropdown .el-select-dropdown__wrap");
if(wrapEl){
wrapEl.addEventListener("scroll", function () {
/**
* scrollHeight 獲取元素內(nèi)容高度(只讀)
* scrollTop 獲取或者設(shè)置元素的偏移值,
* 常用于:計算滾動條的位置, 當(dāng)一個元素的容器沒有產(chǎn)生垂直方向的滾動條, 那它的scrollTop的值默認(rèn)為0.
* clientHeight 讀取元素的可見高度(只讀)
* 如果元素滾動到底, 下面等式返回true, 沒有則返回false:
* ele.scrollHeight - ele.scrollTop === ele.clientHeight;
*/
if (this.scrollTop + this.clientHeight >= this.scrollHeight) {
// binding的value就是綁定的loadmore函數(shù)
binding.value();
}
});
}
},
},
}
</script>
</script>方案三、黃金段位- 虛擬列表
引入社區(qū)的vue-virtual-scroll-list 支持虛擬列表。但這里想的自己再實現(xiàn)一遍虛擬列表,后續(xù)再寫吧。
<template>
<div class="dashboard-editor-container">
<el-select
v-model="value"
clearable
filterable >
<virtual-list
class="list"
style="height: 360px; overflow-y: auto;"
:data-key="'value'"
:data-sources="data"
:data-component="item"
:estimate-size="50"
/>
</el-select>
</div>
</template>
<script>
import VirtualList from 'vue-virtual-scroll-list';
import Item from './item';
export default {
name: 'Demo',
components: {VirtualList, Item},
data() {
return {
options: [],
data: [],
value: '',
pageNo: 0,
item: Item,
}
},
beforeMount() {
this.getList();
},
methods: {
// 模擬獲取大量數(shù)據(jù)
getList() {
const data = [];
for (let i = 0; i < 25000; i++) {
data.push({label: "選擇"+i,value:"選擇"+i});
}
this.allData = data;
this.data = data;
this.getPageList()
},
getPageList(pageSize = 10) {
this.pageNo++;
const list = this.data.slice(0, pageSize * (this.pageNo));
this.options = list;
},
loadMore() {
this.getPageList();
}
}
}
</script>
// item組件
<template>
<el-option :label="source.label" :value="source.value"></el-option>
</template>
<script>
export default {
name: 'item',
props: {
source: {
type: Object,
default() {
return {}
}
}
}
}
</script>
<style scoped>
</style>總結(jié)
最后我們項目中使用的虛擬列表,為啥,因為忽然發(fā)現(xiàn)組件庫支持select是虛擬列表,那就直接使用這個啦。
以上就是解決el-select數(shù)據(jù)量過大的3種方案的詳細(xì)內(nèi)容,更多關(guān)于el-select數(shù)據(jù)量過大的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
關(guān)于eslint和prettier格式化沖突問題
這篇文章主要介紹了eslint和prettier格式化沖突問題,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-08-08
基于vue和bootstrap實現(xiàn)簡單留言板功能
這篇文章主要為大家詳細(xì)介紹了基于vue和bootstrap實現(xiàn)簡單留言板功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-05-05
VUE3中Element table表頭動態(tài)展示合計信息
本文主要介紹了在Vue中實現(xiàn)動態(tài)合計兩個字段并輸出摘要信息的方法,通過使用監(jiān)聽器和深度監(jiān)聽,確保當(dāng)數(shù)據(jù)變化時能正確更新合計結(jié)果,具有一定的參考價值,感興趣的可以了解一下2024-11-11

