解决 Element-ui中 选择器(Select)因options 数据量大导致渲染慢、页面卡顿的问题
业务场景:服务端返回两万多条数据需要在下拉框中展示,直接渲染会导致页面卡顿且需要很长时间等待,用户体验极差,所以我们把这个优化一下el-select,直接上代码。相关知识传送门:Vue 2.x实现自定义指令<template><div class="content"><el-select v-model="chooseValue" filterable v-el-se
·
业务场景:服务端返回两万多条数据需要在下拉框中展示,直接渲染会导致页面卡顿且需要很长时间等待,用户体验极差,所以我们把这个el-select优化一下,直接上代码。
相关知识传送门:
Vue实现自定义指令(directive)及应用场景
Vue中 实现函数的防抖、节流及应用场景
<template>
<div class="content">
<el-select v-model="chooseValue" filterable v-el-select-loadmore="loadMore(rangeNumber)">
<el-option
v-for="(item, index) in options.slice(0, rangeNumber)"
:key="index"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</div>
</template>
<script>
export default {
data() {
return {
chooseValue: "",
options: [],
rangeNumber: 10,
};
},
methods: {
getList() {
// 测试数据25000条数据, 这里数据多少条无所谓,options.slice(0, rangeNumber)方法只会默认加载初始的10条数据
for (let i = 0; i < 25000; i++) {
this.options.push({label: "选择"+i,value:"选择"+i});
}
},
loadMore(n) {
// n是默认初始展示的条数会在渲染的时候就可以获取,具体可以打log查看
// elementui下拉超过7条才会出滚动条,如果初始不出滚动条无法触发loadMore方法
return () => (this.rangeNumber += 5); // 每次滚动到底部可以新增条数 可自定义
},
},
beforeMount() {
this.getList();
},
directives:{
'el-select-loadmore':(el, binding) => {
// 获取element-ui定义好的scroll盒子
const SELECTWRAP_DOM = el.querySelector(".el-select-dropdown .el-select-dropdown__wrap");
if(SELECTWRAP_DOM){
SELECTWRAP_DOM.addEventListener("scroll", function () {
/**
* scrollHeight 获取元素内容高度(只读)
* scrollTop 获取或者设置元素的偏移值,
* 常用于:计算滚动条的位置, 当一个元素的容器没有产生垂直方向的滚动条, 那它的scrollTop的值默认为0.
* clientHeight 读取元素的可见高度(只读)
* 如果元素滚动到底, 下面等式返回true, 没有则返回false:
* ele.scrollHeight - ele.scrollTop === ele.clientHeight;
*/
const condition = this.scrollHeight - this.scrollTop <= this.clientHeight;
if (condition) binding.value();
});
}
},
}
};
</script>
最后, 两万多条数据用户不可能一直滚动下去找自己想要数据,记得设置 filterable 属性,实现搜索功能;
问题: 如果仅设置 element-ui 的 filterable 属性 ,那么搜索的范围只有懒加载已滚动出的数据,导致搜索不全、不准确。
为了解决这个问题,我们又继续使用了 filter-method 属性并结合 visible-change 事件,以及搜索输入时增加防抖进行优化。
最终代码:
// utils.js
function _debounce(fn, delay = 300) {
var timer = null;
return function () {
var _this = this;
var args = arguments;
if (timer) clearTimeout(timer);
timer = setTimeout(function () {
fn.apply(_this, args);
}, delay);
};
}
export {
_debounce
}
<template>
<div class="content">
<el-select
v-model="chooseValue" clearable filterable :filter-method="filterMethod"
v-el-select-loadmore="loadMore(rangeNumber)"
@visible-change="visibleChange">
<el-option
v-for="(item, index) in options.slice(0, rangeNumber)"
:key="index"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</div>
</template>
<script>
import {_debounce} from '@/utils/index.js'
export default {
data() {
return {
chooseValue: "",
options: [],
rangeNumber: 10,
resOptions:[],
};
},
methods: {
// 模拟获取大量数据
getList() {
// 测试数据15000条数据, 这里数据多少条无所谓,options.slice(0, rangeNumber)方法只会默认加载初始的10条数据
for (let i = 0; i < 25000; i++) {
this.resOptions.push({label: "选择"+i,value:"选择"+i});
}
},
loadMore(n) {
// n是默认初始展示的条数会在渲染的时候就可以获取,具体可以打log查看
// elementui下拉超过7条才会出滚动条,如果初始不出滚动条无法触发loadMore方法
return () => (this.rangeNumber += 5); // 每次滚动到底部可以新增条数 可自定义
},
// 筛选方法
filterMethod:_debounce(function(filterVal){
if(filterVal){
let filterArr = this.resOptions.filter((item)=>{
return item.label.toLowerCase().includes(filterVal.toLowerCase())
})
this.options = filterArr;
}else{
this.options = this.resOptions;
}
},500),
// 下拉框出现时,调用过滤方法
visibleChange(flag){
if(flag){
this.filterMethod()
}
},
},
beforeMount() {
this.getList();
},
directives:{
'el-select-loadmore':(el, binding) => {
// 获取element-ui定义好的scroll盒子
const SELECTWRAP_DOM = el.querySelector(".el-select-dropdown .el-select-dropdown__wrap");
if(SELECTWRAP_DOM){
SELECTWRAP_DOM.addEventListener("scroll", function () {
/**
* scrollHeight 获取元素内容高度(只读)
* scrollTop 获取或者设置元素的偏移值,
* 常用于:计算滚动条的位置, 当一个元素的容器没有产生垂直方向的滚动条, 那它的scrollTop的值默认为0.
* clientHeight 读取元素的可见高度(只读)
* 如果元素滚动到底, 下面等式返回true, 没有则返回false:
* ele.scrollHeight - ele.scrollTop === ele.clientHeight;
*/
const condition = this.scrollHeight - this.scrollTop <= this.clientHeight;
if (condition) binding.value();
});
}
},
}
};
</script>
效果:
更多推荐
已为社区贡献40条内容
所有评论(0)