<template>
<el-select
v-model="state.input"
:loading="loading"
loading-text="数据加载中..."
filterable
clearable
popper-class="event-select-poper"
v-el-select-loadmore="loadmore"
placeholder="请输入属性值"
style="width: 100%"
:filter-method="filterOptions"
@change="handleEventsChange"
@visible-change="handleVisibleChange">
<el-option
v-for="item in dataList"
:key="item.id"
:label="item.name"
:value="item.name">
</el-option>
<div style="margin:10 auto; text-align: center; color:#ccc">----已到底----</div>
</el-select>
</template>
<script setup>
import { ref, nextTick } from 'vue';
import axios from 'axios';
const emits = defineEmits(['change'])
const dataList = ref([]); //渲染数据数组
let loading = ref(false)
const state = ref({input: '', val: ''});
const pageIndex = ref(1);
const scrollpSize = ref(10);
const scrollPages = ref(1);
// 自定义v-el-select-loadmore指令
const vElSelectLoadmore = {
beforeMount(el, binding) {
/**
* vue2时:
* el.querySelector('.el-select-dropdown .el-select-dropdown__wrap');
* vue3时:
* 在el-select给一个参数popper-class="event-select-poper"
* element-plus中el-select的选项是使用的popper.js生成的,无法直接获取
*/
const selectDom = document.querySelector('.event-select-poper .el-select-dropdown__wrap')
let loadMores = function() {
/**
* scrollHeight 获取元素内容高度(只读)
* scrollTop 获取或者设置元素的偏移值,常用于, 计算滚动条的位置, 当一个元素的容器没有产生垂直方向的滚动条, 那它的scrollTop的值默认为0.
* clientHeight 读取元素的可见高度(只读)
* 如果元素滚动到底, 下面等式返回true, 没有则返回false:
* ele.scrollHeight - ele.scrollTop === ele.clientHeight;
*/
// 判断是否到底
const isBase = this.scrollHeight - this.scrollTop <= this.clientHeight + 20
if (isBase) {
// 增加防抖
binding.value && binding.value()
}
}
// 将获取到的dom和函数挂载到el-select上,实例销毁时好处理
el.selectDomInfo = selectDom
el.selectLoadMore = loadMores
// 监听滚动事件
selectDom?.addEventListener('scroll', loadMores.bind(selectDom))
},
// 实例销毁
beforeUnmount(el) {
if (el.selectLoadMore) {
el.selectDomInfo.removeEventListener('scroll', el.selectLoadMore)
delete el.selectDomInfo
delete el.selectLoadMore
}
}
}
// onBeforeMount(async () => {
// await loadEvents()
// })
loadEvents();
// 模拟懒加载
const loadmore = () => {
// 数据加载完成之后,不需要再执行懒加载
if (pageIndex.value >= scrollPages.value) { return }
pageIndex.value++
nextTick(() => {
loading.value = true
getList();
loading.value = false
})
}
function getList() {
axios({
method: 'post',
url: 'https://xxx.xx.x.xxx/dataSource/list',
data: { name : state.value.val, pageIndex: pageIndex.value, pageSize: scrollpSize.value },
headers: {'Content-Type': 'application/json;charset=UTF-8'}
}).then(res => {
let resdata = res.data && res.data.data || res.data;
let respage = res.page || (res.data && res.data.page);
for (let index = 0; index < resdata.length; index++) {
dataList.value.push({ name:resdata[index].name, id:resdata[index].id });
}
scrollPages.value = respage.totalPage;
pageIndex.value = respage.pageIndex;
});
}
// 自定义过滤函数
const filterOptions = (query = '') => {
pageIndex.value = 1
nextTick(async () => {
dataList.value = [];
state.value.val = query;
getList();
})
}
// 下拉框隐藏时,重置分页已经过滤得到的列表
const handleVisibleChange = (visible) => {
if(!visible){
pageIndex.value = 1;
}
}
// 获取事件列表
function loadEvents () {
loading.value = true;
getList();
// 调用接口
loading.value = false;
}
const handleEventsChange = (val) => {
console.log(val);
emits('change', val)
}
</script>