类似:表单中有需要选择的下拉框选项太多,选择的时候会因为数据量过大导致页面卡顿,于是对于el-select进行二次封装
value:数据绑定传入的数据
options:选项数据,必填
@visibleChange 下拉框出现/隐藏时触发
@loadMore 滚动加载触发
@remoteMethod 远程搜索触发
@change 选中值发生变化时触发
<template>
<YSelect v-model="form.id" :options="list" :loading="loading" :placeholder="'请选择xxx'" @visibleChange="visibleChange" @loadMore="loadMore" @remoteMethod="remoteMethod" @change="change" />
</template>
<script>
import YSelect from '@/components/ySelect'
export default {
components: { YSelect },
data: {
return {
form: {
id: ''
},
selectForm: {
page: 1,
size: 100,
name: ''
},
loading: false
}
},
methods: {
init: async function() {
this.loading = true
// 获取选项数据,后端需支持 page size name搜索
const res = await getIdOptions({page: this.selectForm.page, size: this.selectForm.size, name: this.select.name})
this.list = res.data
this.loading = false
},
change(value) {
},
visibleChange(status) {
this.select.name = ''
},
loadMore(page) {
this.selectForm.page = page
this.init()
},
remoteMethod(query, page) {
this.selectForm.page = page
this.select.name = query
this.init()
}
}
}
</script>
<template>
<div>
<el-select
v-el-select-loadmore="loadMore"
:value="value"
:loading="loading"
:multiple="multiple"
:placeholder="placeholder"
filterable
remote
:remote-method="(query) => {remoteMethod(query, value)}"
style="width: 100%;"
@change="change"
@input="$emit('input',$event)"
@visible-change="visibleChange"
>
<el-option v-if="hasAll" :label="defaultLabel" value="" />
<el-option
v-for="item in optionsList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</div>
</template>
<script>
export default {
name: 'YSelect',
directives: {
'el-select-loadmore': {
bind(el, binding) {
// 获取element-ui定义好的scroll盒子
const DOM = el.querySelector('.el-select-dropdown .el-select-dropdown__wrap')
DOM.addEventListener('scroll', function() {
/**
* scrollHeight 获取元素内容高度(只读)
* scrollTop 获取或者设置元素的偏移值,常用于, 计算滚动条的位置, 当一个元素的容器没有产生垂直方向的滚动条, 那它的scrollTop的值默认为0.
* clientHeight 读取元素的可见高度(只读)
* 如果元素滚动到底, 下面等式返回true, 没有则返回false:
* ele.scrollHeight - ele.scrollTop === ele.clientHeight;
*/
const condition = this.scrollHeight - this.scrollTop <= this.clientHeight
if (condition) {
binding.value()
}
})
}
}
},
props: {
// 传入的数据,必填
value: {
type: [String, Number, Array],
default: null
},
// 选项数据,必填
options: {
type: Array,
default: () => {
return []
}
},
// 是否有全部选项
hasAll: {
type: Boolean,
default: true
},
defaultLabel: {
type: String,
default: '全部'
},
// 加载loading
loading: {
type: Boolean,
default: false
},
// 提示
placeholder: {
type: String,
default: '请选择'
},
// 是否支持多选
multiple: {
type: Boolean,
default: false
},
// 每次显示数量
size: {
type: Number,
default: 100
}
},
data() {
return {
page: 1,
pageRemote: 1,
defaultLoading: false,
timer: null,
optionsList: [],
oldOptions: [],
isRemote: false
}
},
watch: {
options: {
handler(val) {
if (this.isRemote) {
if (val) {
this.optionsList = val
this.oldOptions = this.oldOptions.filter((item) => {
return !val.some(valItem => item.id === valItem.id)
})
this.oldOptions = [...this.oldOptions, ...val]
}
} else {
if (val) {
this.optionsList = this.optionsList.filter((item) => {
return !val.some(valItem => item.id === valItem.id)
})
this.optionsList = [...this.optionsList, ...val]
}
}
},
deep: true
}
},
mounted() {
this.optionsList = this.options
},
methods: {
change(val) {
this.$emit('change', val)
},
visibleChange(status) {
if (!status) {
if (this.isRemote) {
this.isRemote = false
this.optionsList = [...this.oldOptions]
}
}
this.$emit('visibleChange', status)
},
loadMore() {
console.log(this.isRemote, this.pageRemote, this.page)
if (this.isRemote) {
if (this.pageRemote === 1) {
this.$emit('loadMore', this.pageRemote)
this.pageRemote++
} else {
this.pageRemote++
this.$emit('loadMore', this.pageRemote)
}
} else {
this.page++
this.$emit('loadMore', this.page)
}
},
remoteMethod(query) {
this.pageRemote = 1
if (this.timer) {
clearTimeout(this.timer)
this.timer = null
}
this.timer = setTimeout(() => {
this.isRemote = true
this.oldOptions = [...this.optionsList]
this.optionsList = []
this.$emit('remoteMethod', query, this.pageRemote)
}, 500)
}
}
}
</script>
<style lang='scss' scoped>
</style>