待解决的问题:如何恢复下拉框滚动条的位置到初始高度
<template>
<el-select
v-model="selectedValue"
placeholder="请选择"
ref="selectRef"
@visible-change="handleVisibleChange"
style="width: 150px"
>
<el-option
v-for="item in visibleOptions"
:key="item.value"
:value="item.value"
:label="item.label"
></el-option>
<!-- 如果还有更多数据,显示加载更多的提示 -->
<div v-if="hasMore && !isLoading" class="loading-prompt">加载更多...</div>
<!-- 如果正在加载,显示加载中的提示 -->
<div v-if="isLoading" class="loading-prompt loading-active">
<el-icon class="el-icon-loading"></el-icon> 加载中...
</div>
</el-select>
</template>
<script setup>
import { ref, onMounted, onUnmounted, nextTick } from 'vue';
// import { ElSelect, ElOption, ElIcon } from 'element-plus';
const selectedValue = ref(null);
const visibleOptions = ref([]);
const options = ref([]);
const isLoading = ref(false);
const hasMore = ref(true);
const selectRef = ref(null);
const currentPage = ref(1);
const pageSize = ref(10);
let scrollListenerAdded = false;
// 模拟从后端获取数据的异步函数
async function fetchData() {
await new Promise((resolve) => setTimeout(resolve, 1500));
return Array.from({ length: pageSize.value }, (v, k) => ({
value: `value${(currentPage.value - 1) * pageSize.value + k + 1}`,
label: `选项${(currentPage.value - 1) * pageSize.value + k + 1}`,
}));
}
// 加载数据的函数
async function loadOptions() {
if (isLoading.value) return;
isLoading.value = true;
const newOptions = await fetchData();
visibleOptions.value = visibleOptions.value.concat(newOptions);
isLoading.value = false;
if (newOptions.length < pageSize.value) hasMore.value = false;
}
// 处理下拉框显示和隐藏的函数
const handleVisibleChange = async (visible) => {
if (visible) {
const selectDropdown = document.querySelector(
".el-select-dropdown .el-select-dropdown__wrap"
)
if (!scrollListenerAdded) {
await nextTick();
selectDropdown.addEventListener('scroll', handleScroll);
scrollListenerAdded = true;
}
} else {
if (scrollListenerAdded) {
const selectDropdown = document.querySelector(
".el-select-dropdown .el-select-dropdown__wrap"
)
selectDropdown.removeEventListener('scroll', handleScroll);
scrollListenerAdded = false;
}
// 当下拉框隐藏时,重置分页信息
currentPage.value = 1;
hasMore.value = true;
visibleOptions.value = visibleOptions.value.slice(0, pageSize.value)
}
};
// 滚动加载更多数据的函数
const handleScroll = () => {
const selectDropdown = document.querySelector(
".el-select-dropdown .el-select-dropdown__wrap"
)
const { scrollTop, scrollHeight, clientHeight } = selectDropdown;
if (scrollTop + clientHeight >= scrollHeight && hasMore.value && !isLoading.value) {
loadMore();
}
};
// 加载更多数据的函数
const loadMore = async () => {
if (!hasMore.value || isLoading.value) return;
isLoading.value = true;
currentPage.value++;
const newOptions = await fetchData();
if (newOptions.length > 0) {
visibleOptions.value = visibleOptions.value.concat(newOptions);
} else {
hasMore.value = false;
}
isLoading.value = false;
};
onMounted(async () => {
await nextTick();
await loadOptions();
});
onUnmounted(() => {
if (scrollListenerAdded) {
const selectDropdown = document.querySelector(
".el-select-dropdown .el-select-dropdown__wrap"
)
selectDropdown.removeEventListener('scroll', handleScroll);
scrollListenerAdded = false;
}
});
</script>
<style scoped>
.loading-prompt {
text-align: center;
padding: 8px;
color: #606266;
}
.loading-active .el-icon-loading {
animation: spin 1s infinite linear;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>