antdv的select组件原本是有对大量数据的虚拟滚动的,但是貌似与:dropdownMatchSelectWidth="false"冲突,因此暂且尝试实现了一下动态加载数据。实现的效果不太理想,但也能凑合用,主要问题是无法通过滚动条快速滑动到指定位置,以及无法快速连贯滚动。
<template>
<Select
style="width: 200px"
:onSelect="{()=>{console.log('自行实现相关逻辑')}}"
:options="curFileList"
placeholder="请选择"
:onPopupScroll="handlePopupScroll"
/>
</template>
<script lang="ts" setup>
import { Select } from "ant-design-vue";
import axios from "axios";
import { nextTick, onMounted, Ref, ref } from "vue";
//总列表
const fileList: Ref<{ value: string; label: string }[]> = ref([]);
//下拉框中列表始终维持在这个长度,保持前端始终仅有一条看不到,也就是滑动高度仅有一条数据的高度
const curListSize = 9;
//当前下拉框所使用的curListSize条数据
const curFileList: Ref<{ value: string; label: string }[]> = ref([]);
//fileList中下一个放入curFileList的元素的检索地址
let fileIndex = 0;
onMounted(() => {
loadData();
});
function loadData() {
axios({
method: "get",
url: "/getFileList",
}).then((res) => {
const data = res.data.payload;
if (data) {
for (let i = 0; i < data.length; i++) {
const op = {
value: data[i].value,
label: data[i].label,
};
fileList.value.push(op);
}
//初始化下拉框数据
curFileList.value = fileList.value.slice(0, curListSize);
fileIndex =
curListSize < fileList.value.length
? curListSize
: fileList.value.length;
} else {
alert("数据获取失败");
}
});
}
//动态加载下拉框数据,debounce的第二个参数用来设置触发频率
const handlePopupScroll = debounce(function (e) {
const { target } = e;
// scrollHeight:代表包括当前不可见部分的元素的高度
// scrollTop:代表当有滚动条时滚动条向下滚动的距离,也就是元素顶部被遮住的高度
// clientHeight:包括padding但不包括border、水平滚动条、margin的元素的高度
const rmHeight = target.scrollHeight - target.scrollTop;
const clHeight = target.clientHeight;
// 当下拉框失焦的时候,也就是不下拉的时候
if (rmHeight === 0 && clHeight === 0) {
return;
} else {
// 当下拉框滚动条到达底部或者到达顶部或者总数不够换页的时候,不进行操作
// 当滚动到当前页底部的时候就向curFileList尾部加入下一条数据,删除list头部一条数据;当滚动到当前页顶部时头部加入一条数据,删除list尾部一条数据
if (
(fileIndex >= fileList.value.length &&
target.scrollTop > target.scrollHeight - clHeight - 0.1) ||
(fileIndex <= curListSize && target.scrollTop < 0.1) ||
fileList.value.length <= curListSize
) {
return;
} else {
if (target.scrollTop > target.scrollHeight - clHeight - 0.1) {
let temp = curFileList.value.concat(fileList.value[fileIndex]);
temp.splice(0, 1);
curFileList.value = temp;
//数据更新后滚动到更新前位置
nextTick(() => {
target.scrollTo(0, 0.15);
});
fileIndex++;
}
if (target.scrollTop < 0.1) {
let temp = curFileList.value;
temp.splice(0, 0, fileList.value[fileIndex - curListSize - 1]);
temp.splice(curListSize, 1);
curFileList.value = temp;
nextTick(() => {
target.scrollTo(0, target.scrollHeight - clHeight - 0.15);
});
fileIndex--;
}
}
}
}, 25);
</script>