为 el-select 组件添加滚动加载更多的功能

转载请注明出处,点击此处 查看更多精彩内容

el-select 是 element-ui 组件库提供的下拉选择菜单组件。

在项目中,我们展示到 el-select 的数据通常是从服务端获取的,如果服务端的查询较慢或者数据量过大,就会导致在前端的显示很慢,特别是在网络不好的时候更是如此。

所以,分页展示就是一种较好的交互体验了,可惜的是 el-select 组件并没有提供分页的功能。

本着不重复造轮子(懒)的原则,在网上逛了一圈,发现现有实现方案基本都是基于 el-select 封装了新的组件,这可能导致 el-select 组件的部分功能不可用,并且不是很灵活。

算啦,动手做一个吧。

实现效果

效果图

实现思路

  • 自定义一个组件 ElSelectLoading.vue,由用户自行插入到 el-select 组件菜单的底部。
  • 使用 IntersectionObserver 监听当前组件是否出现在可见范围,可见时触发加载数据的事件。
  • 用户监听事件加载新数据,对 el-select 的功能没有影响。

这个思路也适用于其他的列表监听滚动触底加载更多数据。

实现代码







为什么根组件使用 el-option 而不是 div 或其他标签?
这是因为 el-select 在内部没有任何 el-option 的时候不会渲染菜单浮层,如果使用 div,组件可能会没有机会渲染。

Props:

参数名称 说明 类型 默认值
page 当前页码 number -
loading 是否加载中,用来过滤重复的加载 boolean -
loadingText 加载中的提示文案 string 正在加载
hasMore 是否有更多数据可加载 boolean -
noMoreText 没有更多数据的提示文案 string 到底了~

Emits:

事件名称 说明 回调参数
loadMore 触底可加载数据时触发 (newPage: number)

使用示例






观察代码可以发现,在菜单底部插入了 ElSelectLoading 组件,并在加载数据时更新对应的状态。

注意: 每次 loadMore 事件回调的新页码参数都是由组件 props.page + 1 得到的,因此,

  1. page 参数的值应该由 0 开始。
  2. page.value 的更新应该放在数据加载成功后,以防加载失败后重新加载时页码错误。

如果项目中有多个功能需要分页加载,也可以自行基于 el-select 和 ElSelectLoading 做封装。

分页时数据回显问题的解决方案

默认情况下要回显的数据在菜单里不存在时 el-select 会把 value 展示出来,在分页加载中这种情况是很常见的,对用户很不友好,需要处理一下。

以下方案都建立在回显时已拿到选中项的 valuelabel 值的前提下。

方案一:模拟回显

如果是单选的话,我们可以用 absolute 定位元素覆盖到 el-select 组件上模拟回显 label 值,可以完美回显。

多选的话模拟起来很麻烦,要考虑高度、删除等问题,建议不要用 el-select 组件了,或者看一下方案二吧。

方案二:手动处理数据

根据要回显的 valuelabel 组建一个列表并插入到第一页,后续分页加载时从列表中删除重复数据。

该方案的缺点也很明显:

  1. 回显时会把原本分散的选中数据集中到最前面,有点违反直觉,如果原列表有排序的话,还会导致顺序混乱。
  2. 从后续分页中删除已回显的重复数据后,本页加载到的有效数据量会小于 pagesSize,甚至出现为 0 的情况。

回显方案总结

综上所述,在列表筛选项等不需要回显的场景或者【单选+回显】场景下使用分页加载是比较合适的,【多选+回显】的情况不建议使用 el-select 分页加载,可以考虑用 dialog + table 去做(需要和产品经理 battle 一下),或者去找一找有没有完善的带回显功能的分页下拉菜单组件。

如果大家有好的回显方案,也可以到评论区分享一下。

你可能感兴趣的:(为 el-select 组件添加滚动加载更多的功能)