el-select+vue-virtual-scroller解决数据量大卡顿问题
解决el-select中数据量过大时,显示及搜索卡顿问题,及正确的回显默认选中数据
粗略的封装了组件,有需要各种属性自定义的,自己添加设置下
环境 node 16.20.1 npm 8.19.4
vue2、element-ui
"vue-virtual-scroller": "^1.1.2"
封装组件
selectVirtual.vue
<!-- 下拉多选框 -->
<template><el-selectv-model="selectValue":placeholder="placeholder"popper-class="smallSelectDropdown pop_select_down":class="[defaultClass !== 'no' ? 'selectCheckBox' : '', className]"size="small":multiple="multiple"clearablecollapse-tagsfilterablereserve-keyword:popper-append-to-body="false":filter-method="filterableHandler"@visible-change="selectVisibleChange"@change="selectChange"><div class="el-select-dropdown__empty" v-show="showNoData">无匹配数据</div><recycle-scroller ref="selectCheckBox"class="smallSelectDropdown-scroller":items="selectList":item-size="32":key-field="opv"><template v-slot="{ item }"><el-option:key="item[opv]":label="item[opl]":value="item[opv]"></el-option></template></recycle-scroller></el-select>
</template><script>
import { RecycleScroller } from 'vue-virtual-scroller'
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
let sortOrgList = [];
export default {name: 'SelectCheckBox',components: {RecycleScroller},props: {// 父组件的样式名称defaultClass: {type: String,default: ''},placeholder: {type: String,default: ''},// 样式名称className: {type: String,default: ''},// 对应的el-options的value绑定的字段opv: {type: String,default: 'id'},// label绑定的字段opl: {type: String,default: 'label'},// 父组件传参过来的下拉备选项的初始数据(options用于子组件绑定)optionsOri: {type: Array,default: () => []},multiple: {type: Boolean,default: true},value: {type: Array|String,},},model: {prop: 'value',//要存在于propsevent: 'change'},computed: {showNoData() {return this.selectList.length === 0;}},watch: {value: {handler(val) {if (this.multiple) {this.selectValue = val || []} else {this.selectValue = val || '';}if (this.optionsOri.length && !this.selectVisible && this.selectValue) { sortOrgList = this.dealEcho(this.optionsOri);}},immediate: true},optionsOri: {handler(val) { let list = structuredClone(val);if (val.length && !this.selectVisible && this.selectValue) { sortOrgList = this.dealEcho(val);} else {this.selectList = list;sortOrgList = list;}},immediate: true,deep: true}},data() {return {selectValue: '', // 当前子组件 v-model值isSelectAll: false, // 全选selectVisible: false,// 下拉框显示状态selectList:[]}},methods: {dealEcho(val) {let list = structuredClone(val);//回显默认数据时-由于虚拟滚动不显示全部数据,所以回显会有显示value而不是对应的label,所以将选中的值放到最前面if (this.multiple) {let selectedArr = Array.from(this.selectValue).reverse();selectedArr.map(row => {let findIndex = list.findIndex(item => item[this.opv] === row);if (findIndex != -1) {let obj = list[findIndex];list.splice(findIndex, 1);list.unshift(obj);}})} else {let findIndex = list.findIndex(item => item[this.opv] === this.selectValue);if (findIndex != -1) {let obj = list[findIndex];list.splice(findIndex, 1);list.unshift(obj);}}this.selectList = list;return list;},filterableHandler(value) {this.selectList = this.optionsOri.filter((item) => {return (item[this.opv].indexOf(value) > -1 ||item[this.opl].indexOf(value) > -1)})},// visible-change事件selectVisibleChange(v) {this.selectVisible = v;if (v === false) {this.selectList = structuredClone(this.optionsOri.length==sortOrgList.length?sortOrgList:this.optionsOri);
this.$refs.selectCheckBox?.scrollToItem(0);//滚动到顶部 }},// change事件selectChange(v) {this.$emit('change', v)},}
}
</script>
<style lang="less">
.smallSelectDropdown{overflow-y:hidden;.el-scrollbar__bar.is-vertical{display:none;}.smallSelectDropdown-scroller{max-height:250px;overflow-y:auto;&::-webkit-scrollbar-track{box-shadow: none;background-color: #fff;}}.el-select-dropdown__list{min-width: 240px;}
}</style>
页面引入组件
<SelectVirtual:multiple="false"ref="selectCheckBox"placeholder="请输入名称/编码":options="merchantList":options-ori="merchantList"v-model="filter.merchantNo"opl="merchantName"opv="merchantNo"
/>