FilterSelect.vue
<template>
<el-select
v-model="innerValue"
:disabled="disabled"
filterable
clearable
:placeholder="placeholder"
:filter-method="handleFilter"
@change="changeHandler"
>
<el-option
v-for="item in options"
:key="item[keyField]"
:label="item[labelField]"
:value="item[valueField]"
/>
</el-select>
</template>
<script>
export default {
name: 'FilterSelect',
model: {
// model选项可以自定义prop名称和event名称
prop: 'value',
event: 'handleSelectChange'
},
props: {
// 下拉框数据
value: {
type: String,
default: () => ''
},
selectList: {
type: Array,
default: () => []
},
disabled: {
type: Boolean,
default: () => false
},
placeholder: {
type: String,
default: () => '请选择'
},
labelField: {
type: String,
default: () => 'label'
},
valueField: {
type: String,
default: () => 'value'
},
keyField: {
type: String,
default: () => 'key'
}
},
data() {
return {
// 下拉框实际渲染的数据
options: [],
innerValue: ''
}
},
watch: {
value(val) {
// 将value同步到innerValue
this.innerValue = val
},
options(val) {
// 回显功能
if (
val.length > 0 &&
this.selectList.length > 0 &&
this.valueField &&
this.value
) {
const optionIsContain = val.filter(
(item) => item[this.valueField] === this.value
)
if (optionIsContain.length === 0) {
const activeItem = this.selectList.filter(
(item) => item[this.valueField] === this.value
)[0]
this.options.unshift(activeItem)
}
}
// 长度控制
if (val.length > 30) {
this.options = val.slice(0, 30)
}
},
'selectList.length': function(n, o) {
if (n !== o) {
this._initData()
}
}
},
mounted() {
this._initData()
},
methods: {
// 初始化数据
_initData() {
this.options =
this.selectList.length <= 30
? this.selectList
: this.selectList.slice(0, 30)
// 初始化选中值
this.innerValue = this.value
},
// v-model关键函数
changeHandler(val) {
this.$emit('handleSelectChange', val)
},
// 搜索函数
handleFilter(query) {
if (query !== '') {
this.options = this.selectList
.filter((item) => {
return (
item[this.labelField].toLowerCase().indexOf(query.toLowerCase()) >
-1
)
})
.slice(0, 30)
} else {
this.options =
this.selectList.length > 30
? this.selectList
: this.selectList.slice(0, 30)
}
}
}
}
</script>