背景
某一个下拉选项,数据太多了,需要通过滚动加载分页实现,异步加载数据
实现
el-select 结构
关键是这个 v-select-loadmore:[loadmoreClass]="loadMore"
<el-select
v-model="xxx"
filterable
clearable
placeholder="xxx"
v-select-loadmore:[loadmoreClass]="loadMore"
:popper-class="loadmoreClass"
>
<el-option
v-for="(val, i) in options"
:key="i"
:label="val"
:value="val"
></el-option>
</el-select>
请求数据的方法
const options = ref<string[]>([]);
const PageSize = reactive({
page: 1,
size: 20,
total: 0,
});
// 加载数据
const loadData = async (keyword = '') => {
try {
const res = await fetchList({
page: PageSize.page,
size: PageSize.size,
});
if (res.code === 0) {
options.value = [...options.value, ...res.data.lists];
PageSize.total = res.data.total;
PageSize.page++;
} else {
ElMessage.error(res.msg);
}
} catch (error) {
console.error('加载失败', error);
}
};
// 滚动触底加载
const loadMore = () => {
if (options.value.length < PageSize.total || PageSize.total === 0) loadData();
};
定义一个指令方法
import { debounce } from "lodash";
export const selectLoadMore = {
beforeMount(el, binding) {
const selectDom = document.querySelector(
`.${binding.arg} .el-select-dropdown__wrap`
);
const loadMores = debounce(() => {
// 判断是否到底
const isBase =
selectDom.scrollHeight - selectDom.scrollTop - 10 <=
selectDom.clientHeight;
if (isBase) {
// 可以增加防抖,用户体验会更好,视情况而定
binding.value && binding.value();
}
}, 300);
// 将获取到的dom和函数挂载到el-select上,以便实例销毁时进行事件移除处理
el.selectDomInfo = selectDom;
el.selectLoadMore = loadMores;
// 监听滚动事件
selectDom?.addEventListener("scroll", loadMores);
},
// 实例销毁
beforeUnmount(el) {
if (el.selectLoadMore) {
el.selectDomInfo.removeEventListener("scroll", el.selectLoadMore);
delete el.selectDomInfo;
delete el.selectLoadMore;
}
},
};
定义指令
app.directive('selectLoadmore', selectLoadMore);