解决el-select数据量过大的3种方案
作者:searchop
最近做完一个小的后台管理系统,快上线了,发现一个问题,有2个select的选项框线上的数据量是1w+,而测试环境都是几百的,所以导致页面直接卡住了,本文给大家总结了3种方法,需要的朋友可以参考下
背景
最近做完一个小的后台管理系统,快上线了,发现一个问题,有2个select的选项框线上的数据量是1w+。。而测试环境都是几百的,所以导致页面直接卡住了,over了。
想了一下,如果接口支持搜索和分页,那直接通过上拉加载就可以了。但后端不太愿意改😄。行吧,前端搞也是可以的。
方案
通过一顿搜索加联想总结了3种方法,以下方法都需要支持开启filterable
支持搜索。
标题 | 具体 | 问题 |
---|---|---|
方案1 | 只展示前100条数据,这个的话配合filter-method 每次只返回前100条数据。 | 限制展示的条数可能不全,搜索需要多搜索点内容 |
方案2 | 分页方式,通过指令实现上拉加载,不断上拉数据展示数据。 | 仅过滤加载出来的数据,需要配合filterMethod过滤数据 |
方案3 | options列表采用虚拟列表实现。 | 成本高,需要引入虚拟列表组件或者自己手写 |
方案一,青铜段位 filterMethod直接过滤数据量
<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: { // 模拟获取大量数据 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'); } } }
方案二、 白银段位 自定义滚动指令,实现翻页加载
写自定义滚动指令,options列表滚动到底部后,再加载下一页。但这时候筛选出来的是已经滚动出来的值。
这里如果直接使用filterable来搜索,搜索出来的内容是已经滑动出来的内容。如果想筛选全部的,就需要重写filterMethod方法来自定义过滤功能。可以根据情况选择是否要重写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: { // 模拟获取大量数据 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 获取元素内容高度(只读) * scrollTop 获取或者设置元素的偏移值, * 常用于:计算滚动条的位置, 当一个元素的容器没有产生垂直方向的滚动条, 那它的scrollTop的值默认为0. * clientHeight 读取元素的可见高度(只读) * 如果元素滚动到底, 下面等式返回true, 没有则返回false: * ele.scrollHeight - ele.scrollTop === ele.clientHeight; */ if (this.scrollTop + this.clientHeight >= this.scrollHeight) { // binding的value就是绑定的loadmore函数 binding.value(); } }); } }, }, } </script> </script>
方案三、黄金段位- 虚拟列表
引入社区的vue-virtual-scroll-list 支持虚拟列表。但这里想的自己再实现一遍虚拟列表,后续再写吧。
<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: { // 模拟获取大量数据 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>
总结
最后我们项目中使用的虚拟列表,为啥,因为忽然发现组件库支持select是虚拟列表,那就直接使用这个啦。
以上就是解决el-select数据量过大的3种方案的详细内容,更多关于el-select数据量过大的资料请关注脚本之家其它相关文章!