当前位置:   article > 正文

vue3——利用自定义指令实现下拉框分页懒加载

vue3——利用自定义指令实现下拉框分页懒加载

需求:下拉框一开始请求第一页的内容,滚动到最后的时候,请求第二页的内容,如此反复,直到所有数据加载完成。

selectLoadMore.ts

  1. //自定义指令:实现下拉框下拉到末尾时,加载下一页的内容
  2. // 使用时传两个参数,一个是下拉框的class,一个是下拉框滚动到末尾时触发的函数,比如:
  3. // v-el-select-loadmore="{
  4. // selector: '.myOption .el-select-dropdown .el-select-dropdown__wrap',
  5. // loadFunction: loadMore
  6. // }"
  7. export default {
  8. mounted(el, binding) {
  9. //解构传来的值
  10. const {
  11. value: { selector, loadFunction }
  12. } = binding
  13. const SELECTWRAP_DOM = document.querySelector(selector)
  14. if (SELECTWRAP_DOM) {
  15. // 监听事件的处理函数,把函数单独写出来,方便销毁
  16. const scrollHandler = () => {
  17. const condition = SELECTWRAP_DOM.scrollTop + SELECTWRAP_DOM.clientHeight >= SELECTWRAP_DOM.scrollHeight - 1
  18. if (condition) {
  19. loadFunction()
  20. }
  21. }
  22. //赋值,为了方便销毁,这里很重要,不然销毁的时候找不到dom和对应的回调函数!!!
  23. el.dom = SELECTWRAP_DOM
  24. el.event = scrollHandler
  25. //监听滚动事件
  26. SELECTWRAP_DOM.addEventListener('scroll', scrollHandler)
  27. }
  28. },
  29. //销毁,会在关闭弹窗时触发(这里的el-select写在弹窗里)
  30. beforeUnmount(el) {
  31. if (el.dom) {
  32. el.dom.removeEventListener('scroll', el.event)
  33. }
  34. }
  35. }

记得在main.ts里面注册成全局组件!!!! 

main.ts

  1. import vElSelectLoadmore from '@/utils/tools/selectLoadMore'
  2. app.directive('el-select-loadmore', vElSelectLoadmore) //全局自定义指令
  3. app.mount('#app')

使用的vue文件 

  1. //使用时在指令里传值,这里有个坑!
  2. //在el-select给一个参数popper-class="myOption",因为element-plus中ei-select的选项是使用的popper.js生成的,无法直接获取,直接获取下拉框的dom获取不到
  3. <el-select
  4. v-el-select-loadmore="{
  5. selector: '.myOption .el-select-dropdown .el-select-dropdown__wrap',
  6. loadFunction: loadMore
  7. }"
  8. v-model="userForm.accountName"
  9. placeholder="请选择用户"
  10. popper-class="myOption"
  11. >
  12. <el-option
  13. v-for="(item, index) in userData"
  14. v-loading="optionLoading(index)"
  15. :key="item.id"
  16. :label="item.username"
  17. :value="item.id"
  18. />
  19. </el-select>
  20. //总共的数据条数
  21. let totalCount: number = 0
  22. //当前滚动页
  23. let page: number
  24. /**
  25. * 自定义指令触发的回调
  26. */
  27. function loadMore() {
  28. //计算总页数
  29. let maxPagSize: number = Math.max(Math.ceil(totalCount / 10), 1)
  30. //不超过总页数才发请求
  31. if (page < maxPagSize) {
  32. page += 1
  33. //发请求,获得接口数据
  34. getUserListWrap(page, 10)
  35. }
  36. }
  37. /**
  38. * 控制下拉框loding是否出现,isOptionLoading是在getUserListWrap请求函数里面的,userData是请求函数获得是下拉框数据,这样可以使下拉到最后一个option的时候,出现loding效果,更加完善美观
  39. * @param index 下拉框循环的index
  40. */
  41. function optionLoading(index: number): boolean {
  42. if (isOptionLoading.value && index == userData.length - 1) {
  43. return true
  44. } else {
  45. return false
  46. }
  47. }

总结:

1、 在el-select给一个参数popper-class="myOption",因为element-plus中el-select的选项是使用的popper.js生成的,无法直接获取,直接获取下拉框的dom获取不到

2、在自定义指令里面销毁事件的时候,在mounted必须把事件存在el上,不然不好销毁,一开始是以下这么写的:发现这样不好销毁,因为在 beforeUnmount拿不到function,this只能按以下这么写才行,如果单独把funtion拎出来,this就报错找不到

  1. export default {
  2. mounted(el, binding) {
  3. const {
  4. value: { selector, loadFunction }
  5. } = binding
  6. const SELECTWRAP_DOM = document.querySelector(selector)
  7. if (SELECTWRAP_DOM) {
  8. SELECTWRAP_DOM.addEventListener('scroll', function () {
  9. const condition = this.scrollTop + this.clientHeight >= this.scrollHeight - 1
  10. if (condition) {
  11. loadFunction()
  12. }
  13. })
  14. }
  15. }
  16. }

 vue3的demo代码如下:

  1. <template>
  2. <el-form-item label="用户名称:">
  3. <el-select
  4. popper-class="myOption"
  5. v-model="accountName"
  6. placeholder="请输入或选择用户"
  7. v-el-select-loadmore="loadMore">
  8. <el-option v-for="item in options"
  9. :key="item.value"
  10. :label="item.label"
  11. :value="item.value" />
  12. </el-select>
  13. </el-form-item>
  14. </template>
  15. <script setup lang="ts">
  16. import {ref,onMounted} from 'vue'
  17. let page = ref(1)
  18. let pageSize = ref(10)
  19. let total = 100
  20. let totalCount=6
  21. let stopLoading = false
  22. let accountName = ref('')
  23. const options = ref([])
  24. onMounted(() => {
  25. options.value.length=0
  26. loadOptions(1)
  27. })
  28. function loadMore() {
  29. //这里设置接口的最大页数totalCount为6,超过6页就没数据了
  30. if (page.value <= totalCount) {
  31. page.value += 1;
  32. //获得接口数据
  33. loadOptions(page.value);
  34. }
  35. }
  36. function loadOptions(page:number) {
  37. // 模拟接口发送数据,异步加载数据
  38. setTimeout(() => {
  39. for (let i = (page-1)*10+1; i <= page*10; i++) {
  40. options.value.push({
  41. value: `Option${i}`,
  42. label: `Option${i}`
  43. });
  44. }
  45. }, 500);
  46. }
  47. //在自定义指令
  48. const vElSelectLoadmore = {
  49. mounted(el: any, binding: any) {
  50. // 坑:
  51. const SELECTWRAP_DOM:Element|null = document.querySelector(
  52. '.myOption .el-select-dropdown .el-select-dropdown__wrap'
  53. );
  54. if (SELECTWRAP_DOM) {
  55. SELECTWRAP_DOM.addEventListener('scroll', function () {
  56. const condition = this.scrollTop+this.clientHeight >= this.scrollHeight-1;
  57. // 当滚动条滚动到最底下的时候执行接口加载下一页
  58. if (condition) {
  59. binding.value && binding.value()
  60. }
  61. });
  62. }
  63. },
  64. }
  65. </script>

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/神奇cpp/article/detail/903945
推荐阅读
相关标签
  

闽ICP备14008679号