解決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"
/>