概述
使用过ElementUI 2.0组件库的小伙伴都知道,在下拉列表数据量大的情况会出现页面卡顿、无响应的情况;这时候我们想到通过虚拟下拉列表来解决,而ElementUI 2.0中并没有这种组件,此时就需要我们对下拉列表做二次开发才能实现。
实现效果
一、下拉列表子组件virtualOption
export default {
name: 'virtualOption',
props: {
index: { // 每一行的索引
type: Number
},
label: String,
value: [String, Number],
source: { // 每一行的内容
type: Object,
default: () => ({})
}
},
render() {
let label = this.source[this.label]
let value = this.source[this.value] || this.source
return (<el-option label={label} value={value}></el-option>)
}
}
二、下拉列表组件
<template>
<el-select v-model="defaultValue" :filter-method="filterMethod" filterable @visible-change="visibleChange" placeholder="请选择">
<virtual-list
ref="virtualList"
:data-sources="options"
data-key="value"
:estimateSize="34"
:keeps="keeps"
:data-component="virtualOption"
:extra-props="{ label: 'label', value: 'value' }"
style="max-height: 245px; overflow-y: auto;">
</virtual-list>
</el-select>
</template>
<script>
import VirtualList from 'vue-virtual-scroll-list'
import VirtualOption from './virtualOption'
export default {
name: 'virtual-select',
props: {
list: {
type: Array,
default: () => [],
},
},
components: {
VirtualList,
},
data() {
return {
options: [],
keeps: 25,
defaultValue: '',
virtualOption,
}
},
watch: {
list(val) {
this.options = JSON.parse(JSON.stringify(val))
}
},
methods: {
// 更新下拉搜索框数据
filterMethod(keyword) {
this.$refs.virtualList.reset()
if (!keyword) {
this.options = this.list
this.visibleChange(true)
} else {
const data = this.list.filter(v => v.label.toLowerCase().includes(keyword.toLowerCase()))
this.options = data
}
},
// 显示隐藏更新下拉显示数据范围
visibleChange(bool) {
let virtualList = this.$refs.virtualList
if (bool) {
let index = this.options.findIndex(v => v.value === this.defaultValue)
if (index > -1) {
this.$nextTick(() => {
// 滚动到选中的下拉项
virtualList.scrollToIndex(index)
// 找到最后一组选中下拉项第一条位置
let keeps = this.keeps
if (index >= (this.options.length - keeps)) {
index = this.options.length - keeps
}
// 更新虚拟列表范围,不更新会出现下拉列表会出现空白
virtualList.virtual.updateRange(index, index + keeps)
})
} else {
virtualList.reset()
}
} else {
// 重置
virtualList.reset()
this.options = this.list
}
}
}
}
</script>