el-select 下拉框增加滚动条滚到底部加载分页数据

第一步,创建select-load-more.js文件

// 定义全局自定义指令
import Vue from 'vue'

const selectLazyLoad = function(Vue) {
  // el-select组件数据过多,使用翻页加载数据指令
  Vue.directive('selectLazyLoad', {
    bind(el, binding) {
      const SELECT_WRAP_DOM = el.querySelector('.el-select-dropdown .el-select-dropdown__wrap')
      SELECT_WRAP_DOM.addEventListener('scroll', function() {
        // toFixed:把this.scrollTop转换为整数,兼容不同版本浏览器
        const condition = this.scrollHeight - this.scrollTop.toFixed(0) <= this.clientHeight
        if (condition) binding.value()
      })
    }
  })
}

if (window.Vue) {
  Vue.use(selectLazyLoad)
}

export default selectLazyLoad

第二步, 在main.js中注册引入自定义指令

import selectLazyLoad from './directive/select-load-more'    //引入
Vue.use(selectLazyLoad)    // 使用自定义指令

第三步, 创建公共组件并在组件中使用自定义指令v-selectLazyLoad

<template v-slot>
  <el-select
    v-model="currentBranchNumber"
    v-selectLazyLoad:pageNum="loadMoreData(pageNum)"
    class="w-72"
    :dropdown-style="{maxHeight: '400px', overflow: 'auto'}"
    placeholder="可根据机构ID或机构名称筛选"
    filterable
    clearable
    remote
    :remote-method="onSearch"
    :loading="loading"
    @clear="clearSelect"
    @focus="focusSelect"
  >
    <el-option v-for="item in branchTreeData" :key="item.id" :label="item.name" :value="item.id" />
  </el-select>
</template>

<script>
import axios from 'axios'
export default {
  name: 'BranchTreeSelect',
  props: {
    branchNumber: {
      type: String,
      default: ''
    }
  },
  data() {
    return {
      branchTreeData: [],
      pageNum: 1,
      currentBranchNumber: '',
      allowSearchFlag: true, // 是否允许检索, 防止连续输入时未组装好数据就再次检索
      loading: false,
      queryParam: { // 查询后端所用参数对象, 可根据自己需求变更请求参数对象
        'xCode': '', // 模糊检索code
        'xName': '', // 模糊检索name
        'xParentCode': 'AYBBRNNO',
        'xType': '',
        'xFormat': 'Y',
        'xPage': 1,
        'xPageSize': 50
      }
    }
  },
  watch: {
    'currentBranchNumber': { // 选中数据改变时,调用父组件的setBranchNumber方法,并传入选中的值
      handler(val) {
        if (val) {
          this.$emit('setBranchNumber', this.currentBranchNumber.toString().split(':')[0])
        } else {
          this.$emit('setBranchNumber', '')
        }
      }
    },
    'pageNum': { // 当前页数改变时, 重新触发查询
      handler(val) {
        if (val) {
          this.queryParam.xPage = val
          this.queryBranchData('', true)
        }
      }
    }
  },
  created() { // 组件实例创建后(data和methods已经初始化完毕), 请求后端数据
    this.queryBranchData()
  },
  methods: {
    loadMoreData() { // 数据到底部继续滑动,会自动触发页数+1
      return () => {
        this.pageNum += 1
      }
    },
    onSearch(val) { // 检索功能, 后端可以支持模糊检索
      if (val) {
        if (this.allowSearchFlag && val.length > 2) { // 输入超过两个字符进行检索
          this.allowSearchFlag = false
          this.branchTreeData = []
          this.queryParam.xPage = 1
          this.queryBranchData(val)
        }
      }
    },
    queryBranchData(param, appendFlag) { // 请求后端数据
      const cacheUrl = 'http://XXXXXXXXX.uat.cn/cache/queryParamPager'
      if (!isNaN(parseInt(param)) && isFinite(param)) {
        this.queryParam['xCode'] = param
      } else if (param && param.trim() !== '') {
        this.queryParam['xName'] = param
      }
      axios.post(cacheUrl, this.queryParam, {
        headers: { 'Content-Type': 'application/json' },
        withCredentials: false
      }).then(res => {
        if (res.data.code === 200 && res.data.data.list.join() !== '') { // 如果后端返回数据有值
          if (appendFlag) { // 是否拼接数据
            this.branchTreeData = this.branchTreeData.concat(res.data.data.list)
          } else {
            this.branchTreeData = res.data.data.list
          }
          this.allowSearchFlag = true
          this.loading = false
        }
      }).catch(err => console.error(`获取机构参数异常, ${err}`))
    },
    clearSelect() { // 清空下拉框选中的值,会向后端重新查询第一页的数据
      this.queryParam['xCode'] = ''
      this.queryParam['xName'] = ''
      this.queryParam.xPage = 1
      this.branchTreeData = []
      this.queryBranchData()
    },
    focusSelect() { // 光标触发下拉框时,如果下拉框数据为空,则向后端查询第一页数据
      if (this.branchTreeData.join() === '') {
        this.queryParam['xCode'] = ''
        this.queryParam['xName'] = ''
        this.queryBranchData()
      }
    }
  }
}
</script>

<style scoped>

</style>

第四步, 在父组件中引入第三步创建的子组件

// 使用第三步创建的子组件
<branch-tree-select ref="accBranchRef" :branch-number="QueryProtocolListX1.accBranch" @setBranchNumber="setAccBranchNumber" />

// 引入子组件
import BranchTreeSelect from '@/components/BranchTreeSelect'

components: {
    BranchTreeSelect
}

mothods: {
    setAccBranchNumber(val) {
      // val就是子组件选中的值
    }
}

以上内容四个步骤从下面链接复制https://devpress.csdn.net/vue/66caf7da8f4f502e1cfda77e.html

以下内容四个步骤从下面链接复制
https://www.cnblogs.com/caihongmin/p/17920859.html
自定义指令

import { debounce } from "lodash";
export default {
    inserted(el, binding, vnode) {
        // 获取滚动容器dom
        let scrollWrap = el.querySelector('.el-select-dropdown .el-scrollbar .el-select-dropdown__wrap')
        // 把监听的句柄防抖一下
        const handle = debounce((e) => {
            let scrollDistance = scrollWrap.scrollHeight - scrollWrap.scrollTop
            // 比如此处预留6个像素的位置用于触底
            if (scrollWrap.clientHeight + 6 > scrollDistance) {
                binding.value() // 触底通知一下,外界
            }
        }, 170)
        // 绑定监听滚动事件
        scrollWrap?.addEventListener('scroll', handle)
        // 把监听的句柄挂载到元素身上便于解绑时使用
        el._hanlde = handle
    },
    unbind() {
        // 获取滚动容器dom
        let scrollWrap = el.querySelector('.el-select-dropdown .el-scrollbar .el-select-dropdown__wrap')
        // 解绑
        scrollWrap?.removeEventListener('scroll', el._hanlde)
        // 清空
        delete el._hanlde;
    }
}

给el-select使用这个自定义指令

<template>
  <div class="box">
    <el-select v-model="value" filterable :popper-append-to-body="false" v-down="loadmore" clearable>
      <el-option v-for="item in options" :key="item.id" :label="item.name" :value="item.id">
      </el-option>
    </el-select>
  </div>
</template>

<script>
import axios from "axios";
export default {
  data() {
    return {
      options: [],
      value: '',
      pageIndex: 1,
      pageSize: 20
    };
  },
  mounted() {
    this.getOptions()
  },
  methods: {
    async getOptions() {
      // 笔者自己的服务器,给大家提供了一个分页接口
      let url = `http://ashuai.work/api/pageData?pageIndex=${this.pageIndex}&pageSize=${this.pageSize}`
      let { data } = await axios.get(url)
      if (data.length == 0) return this.$message('没数据了')
      // 合并一下下拉框数据
      this.options = [
        ...this.options,
        ...data
      ]
    },
    // 触底了,继续发请求
    loadmore() {
      this.pageIndex = this.pageIndex + 1
      this.getOptions()
    },
  },
};
</script>
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容