<template>
<el-select
v-model="modelValue"
:placeholder="placeholder"
:popper-class="popperClassStyle"
:clearable="clearable"
:disabled="disable"
@visible-change="visibleChange"
>
<div :style="{ transform: `translateY(${scrollTopWrapper}px)` }">
<el-option
v-for="item in showItem"
:label="item[selectProps.label]"
:value="item[selectProps.value]"
:key="item[selectProps.value]"
:disabled="item[selectProps.disable]"
></el-option>
<el-option
label=""
:value="-1"
:disabled="true"
v-if="options.data && options.data.length && isvirtualizedFlag"
>
<p
style="height: 30px; text-align: center"
v-if="
searchObj.page < Math.ceil(searchObj.total / searchObj.page_size)
"
>
<span style="margin-right: 6px">加载中</span
><el-icon><Loading /></el-icon>
</p>
<template v-else>
<p style="height: 30px; text-align: center" v-if="!loading">
<span style="margin-right: 6px">已经到底啦~~</span>
</p>
</template>
</el-option>
<el-option
label=""
:value="-999"
:disabled="true"
v-if="!options.data.length && !loading"
>
<span>暂无数据</span>
</el-option>
</div>
</el-select>
</template>
<script>
import { cloneDeep } from "lodash-unified";
export default {
props: {
placeholder: {
type: String,
default: "请选择",
},
clearable: {
type: Boolean,
default: false,
},
value: {
type: [String,Number],
default: "",
},
selectProps: {
type: Object,
default: () => {
return {
label: "title",
value: "id",
disable:'disabled'
};
},
},
disable:{
type: Boolean,
default: false,
},
httpRequest: {
type: Function,
default: () => {},
},
},
data() {
return {
startKey: 0,
showItemNum: 0,
showItemDomHeight: 0,
scrollTopWrapper: 0,
options: {
data: [],
total: 0,
},
searchObj: {
page: 1,
page_size: 10000,
},
isvirtualizedFlag: false,
loading: true,
refDom: "",
};
},
computed: {
wrapHeight() {
return this.showItemDomHeight * this.options.data.length;
},
modelValue: {
get() {
return cloneDeep(this.value);
},
set(news) {
this.$emit("input", news);
// return news;
},
},
showItem() {
console.log(this.isvirtualizedFlag,'this.isvirtualizedFlag---')
return this.isvirtualizedFlag
? [
...this.options.data.slice(
this.startKey,
this.showItemNum + this.startKey + 3
),
]
: cloneDeep(this.options.data);
},
watchData(){
const {options,showItemDomHeight} = this
return {options,showItemDomHeight}
},
popperClassStyle (){
return !this.isvirtualizedFlag?'no-virtualized-select virtualized-select': 'virtualized-select'
}
},
methods: {
visibleChange(value) {
if (value) {
if (!this.refDom) {
this.$nextTick(() => {
this.refDom = document.querySelector(
".virtualized-select .el-scrollbar__wrap"
);
this.showItemDomHeight = document.querySelector(
".virtualized-select .el-scrollbar__wrap .el-select-dropdown__item"
).offsetHeight;
this.showItemNum = Math.ceil(
this.refDom.clientHeight / this.showItemDomHeight
);
this.isvirtualizedFlag =
this.showItemNum < this.options.data.length;
if (!this.isvirtualizedFlag) {
return;
}
this.refDom.addEventListener("scroll", this.scrollLoad, false);
});
}
}
},
scrollLoad(e) {
const dom = e.target;
let clientHeight = dom.clientHeight;
let scrollHeight = dom.scrollHeight;
let tempNum = Math.floor(e.target.scrollTop / this.showItemDomHeight);
if (tempNum === 0) {
this.scrollTopWrapper = 0;
}
if (tempNum !== this.startKey) {
this.startKey = tempNum;
this.scrollTopWrapper = e.target.scrollTop;
}
if (
clientHeight + e.target.scrollTop + 20 >= scrollHeight &&
!this.loading &&
this.searchObj.page <
Math.ceil(this.options.total / this.searchObj.page_size)
) {
this.loading = true;
this.searchObj.page++;
this.getOptions(true);
}
},
async getOptions(flag) {
const res = await this.httpRequest(this.searchObj);
console.log(res,'res----')
this.loading = false;
if (flag) {
this.options.data = [...this.options.data, ...res.data];
this.options.total = res.total;
} else {
this.options.data = res.data;
this.options.total = res.total;
}
},
},
watch:{
watchData(news){
if(!this.isvirtualizedFlag) {
return
}
document.querySelector('.virtualized-select .el-scrollbar__view').style.height = news.options.data.length * news.showItemDomHeight + 'px'
}
},
beforeMount(){
this.getOptions()
},
beforeDestroy(){
this.refDom&& this.refDom.removeEventListener('scroll',this.scrollLoad)
}
};
</script>
<style lang="less">
.virtualized-select {
height: 270px;
.el-select-dropdown__item {
width: 250px;
}
&.no-virtualized-select {
height: auto;
}
}
</style>