el-select下拉菜单无限滚
当我们在工作中需要使用到下拉菜单来使用数据,不管是有没有开启远程搜索,在面对数据量特别大的时候又正好遇到需要开启无限滚动的需求,而原生的elementplus组件库中的el-select又没有一个api可以满足这个需要,那么我们除了自己去封装一个下拉菜单,此时就可以在全局封装一个自定义指令来解决这个问题
注册一个Vue的自定义指令,每当使用el-select滚动到列表底部的时候就请求下一页数据,来达到下拉滚动加载更多的目的。
1. 首先创建一个loadmore.ts
export default {
mounted(el, binding) {
// 延迟执行,确保元素已渲染完成
setTimeout(() => {
// 查找 el 元素中的 .el-select-dropdown .el-select-dropdown__wrap 元素
const selectWrapper = el.querySelector('.el-select-dropdown .el-select-dropdown__wrap');
if (selectWrapper) {
// 给 selectWrapper 添加 scroll 事件监听器
selectWrapper.addEventListener('scroll', function() {
const scrollHeight = this.scrollHeight; // 获取元素的滚动高度
const scrollTop = this.scrollTop; // 获取元素的滚动条垂直位置
const clientHeight = this.clientHeight; // 获取元素的可见高度
// 如果滚动到接近底部的位置(距离底部小于等于 5 像素)
if (scrollTop + clientHeight >= scrollHeight - 5) {
// 调用指令的绑定值(通常是一个方法)
binding.value();
}
});
}
}, 0); // 延迟时间为 0,确保代码在当前同步代码执行完成后执行
},
// 指令被解绑时调用的钩子
unmounted(el) {
// 查找 el 元素中的 .el-select-dropdown .el-select-dropdown__wrap 元素
const selectWrapper = el.querySelector('.el-select-dropdown .el-select-dropdown__wrap');
if (selectWrapper) {
// 移除 scroll 事件监听器
selectWrapper.removeEventListener('scroll');
}
}
};
首先要注意使用时需要用setTimeout来包裹防止dom元素生成的慢从而导致的报错,
el 代表绑定指令的 DOM 元素,从el中拿到.el-select-dropdown .el-select-dropdown__wrap 也就是下拉菜单
unmounted用于注销指令,其余内容可查看注释
2.在全局中注册
- 在全局中注册自定义指令
import selectLoadMore from '@/utils/loadmore.js';
const app = createApp(App)
app.directive('selectLoadMore', selectLoadMore);
3.在下拉菜单中使用
在需要的地方使用自定义指令,需要注意的地方在于必须要加一个:teleported="false",
他的含义是
| teleported | 是否将下拉列表插入至 body 元素 |
|---|
因为下拉菜单的组件teleported默认值为true,默认会插入到body中的,这会导致自定义指令不生效,他所挂载的组件中找不到.el-select-dropdown .el-select-dropdown__wrap
当设置:teleported="false",时要注意下拉菜单的层级关系防止页面覆盖掉下拉菜单
<el-select
v-model="detailData.custId"
filterable
remote
clearable
reserve-keyword
:placeholder="$trans('accountManagement.pleasesecustomer')"
remote-show-suffix
:remote-method="remoteMethodcustName"
:loading="loading"
@clear="queryCustomerMapListFunc"
v-selectLoadMore="loadMore"
:teleported="false"
>
<el-option
style="width:400px"
v-for="item in custNameList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
之后就是正常的无限滚动的方法
const loadMore = () => {
// 实现加载更多数据的逻辑
++listQuery.value.pageNo
// 模拟加载更多数据
queryCustomerMapList({ custIdList: {}, ...listQuery.value }).then((res) => {
const data = res.data.map((item) => ({
label: item.custName,
value: item.custId,
}))
custNameList.value = [...custNameList.value,...data]
})
}