JS是单线程,浏览器的处理和渲染能力都很差,碰到下拉框数据超过3000条就会有卡顿,基于element-UI的select我做了一个下拉框筛选的封装,可以控制前台显示下拉框中数据的数量
父组件使用案例:
- formAttr 相当于v-model
- options 下拉数据
- max 下拉框展示的条数
- 当下拉数据中属性不是value和label时,传一个myOptions,例:{value:'id',label:'text'}
<filter-select
:formAttr.sync="form.name"
:options="nameList"
:max="10"
:myOption="myOption"
>
</filter-select>
<script>
import filterSelect from '../modules/filterSelect.vue';
export defaule {
components: { filterSelect },
data() {
return {
form: {
name: '',
},
nameList: [
{ id: 1, text: 'hello1' },
{ id: 2, text: 'hello2' },
{ id: 3, text: 'hello3' },
],
myOption: { value: 'id', label: 'text' },
},
}
}
</script>
子组件HTML部分:
<template>
<!-- 基于el-select对后台返回超大下拉数据处理 -->
<el-select
v-model="attr"
filterable
:clearable="clearable"
:filter-method="selectFilter"
:allow-create="allowCreate"
:myOption="myOption"
@change="change"
@visible-change="visibleChange"
@clear="clear"
@blur="blur"
>
<el-option
v-for="item in selectList"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</template>
JS部分
export default {
/**
* 使用案例:
* <filter-select
:formAttr='form.name'
:options='nameList'
:max='100'
:myOption='myOption'
>
</filter-select>
父组件中data定义myOption,
如果后台返回的下拉数据不是[{value:'hb',label:'河北'},{value:'bj',label:'北京'}]
而是[{proID:'hb',province:'河北'},{proID:'bj',province:'北京'}]
此时就可以通过 myOption:{value:'province' , label:'proID'}
*/
name: 'filterSelect',
props: {
// form表单的绑定值,比如 form.num
formAttr: {
required: true,
type: [String, Number],
default: '',
},
// 下拉数据的属性,一般为value和label,但也有不是的情况,比如返回的是id 和 text
myOption: {
type: Object,
default: () => {
return {
value: 'value',
label: 'label',
};
},
},
// 父组件传过来的下拉数据
options: {
required: true,
default: () => [],
},
// 最多展示的条数
max: {
type: [Number, String],
default: () => 50,
},
// 是否禁用
disabled: {
type: Boolean,
default: () => false,
},
// 是否可以清空
clearable: {
type: Boolean,
default: () => false,
},
// 是否支持创建条目
allowCreate: {
type: Boolean,
default: () => false,
},
},
computed: {},
watch: {
// 监听下拉框数据,发生变化执行下拉数据过滤截取
options: {
handler() {
this.selectFilter();
},
deep: true,
},
formAttr:{
handle(n){
this.attr = n
},
immediate:true
}
},
data() {
return {
attr: this.formAttr,
selectList: [],
};
},
methods: {
// query是输入的值
selectFilter(query = '') {
let arr = this.options.map(obj => {
return { value: obj[this.myOption.value], label: obj[this.myOption.label] };
});
console.log(arr);
arr = arr.filter(item => {
return (
item.value.toString().toLowerCase().includes(query) ||
item.label.toString().toLowerCase().includes(query)
);
});
if (arr.length > this.max) {
this.selectList = arr.splice(0, this.max);
} else {
this.selectList = arr;
}
},
// 父组件事件可以直接参照 element-UI 的方法执行
change(val) {
this.$emit('update:formAttr',val)
this.$emit('change', val);
},
// 下拉框出现/隐藏时触发
visibleChange(val) {
this.$emit('visibleChange', val);
},
// 可清空的单选模式下用户点击清空按钮时触发
clear() {
this.$emit('clear');
},
// 当 input 失去焦点时触发
blur(e) {
this.$emit('blur', e);
},
// 当 input 获得焦点时触发
focus(e) {
this.$emit('focus', e);
},
},
mounted() {
// this.selectList = this.options.map(item => {
// return { value: item[this.myOption.value], label: item[this.myOption.label] };
// });
},
};
it's over.
有哪里不理解的可以留言或者联系我,这个也可以改成输入内容向后端请求