element-ui中el-select无限滚动

1 篇文章 0 订阅

1. 在main.js同级创建directive.js文件

directive.js:

import Vue from 'vue'

Vue.directive('loadMore', {
  bind(el, binding) {
    // 如果有method由调用方实现,没有则在这里实现加载和远程搜索的功能
    if (binding.modifiers.method) { // 方法一
      // 节流
      let timer
      // 滚动监听
      el.querySelector('.el-select-dropdown .el-select-dropdown__wrap').addEventListener('scroll', function() {
        const condition = this.scrollHeight - this.scrollTop <= this.clientHeight + 100
        if (!timer && condition) {
          // 滚动加载(调用自定义的加载方法)
          binding.value()
          timer = setTimeout(() => {
            clearTimeout(timer)
            timer = null
          }, 500)
        }
      })
    } else { // 方法二
      // 传入的对象
      let value = binding.value
      // 节流
      let timer
      // 无搜索内容变量
      let pageNo = 1
      let pages = 1
      // 远程搜索内容变量
      let searchPageNo = 1
      let searchPages = 1
      // 每次加载的条数
      let pageSize = isNaN(value.pageSize) ? 10 : parseInt(value.pageSize)
      // 远程搜索变量
      let searchField = value.searchField
      // 搜索固定内容
      let searchData = value.searchData
      // 接口地址
      let url = value.url
      // 下拉数组,这个options在本方法中必须永远指向value.options,否则整个功能都将失效
      let options = value.options
      // 无搜索拷贝数组,此处是为了在加载的基础上加一些默认的下拉项
      let optionsCopy = JSON.parse(JSON.stringify(value.options))
      // 远程搜索拷贝数组
      let optionsSearch = []
      // 远程搜索内容
      let searchValue = ''
      // 加载逻辑
      const loadOptions = (searchField, search, searchData) => {
        let params = {
          pageSize: pageSize
        }
        if (searchData) {
          Object.assign(params, searchData)
        }
        // 这里不能改变options的指向,否则会使整个功能失效(不能用options = [])
        options.length = 0
        // 判断是否为远程搜索,true-是
        if (searchField && search) {
          // 当到最大页数时不再查询
          if (searchPages >= searchPageNo) {
            params.pageNo = searchPageNo++
            params[searchField] = search
            api[url](params).then(res => {
              if (res) {
                searchPages = Math.ceil(res.data.total / pageSize)
                optionsSearch = optionsSearch.concat(res.data.data)
                dataProcessing(optionsSearch)
              }
            })
          }
        } else {
          // 当到最大页数时不再查询
          if (pages >= pageNo) {
            params.pageNo = pageNo++
            api[url](params).then(res => {
              if (res) {
                pages = Math.ceil(res.data.total / pageSize)
                optionsCopy = optionsCopy.concat(res.data.data)
                dataProcessing(optionsCopy)
              }
            })
          }
        }
      }
      // 返回数据处理
      let dataProcessing = (optionsCopy) => {
        // 这里不能改变options的指向,否则会使整个功能失效
        optionsCopy.forEach(item => {
          let check = options.find(t => {
            return t[value.modelField] === item[value.modelField]
          })
          if (!check) {
            options.push(item)
          }
        })
      }
      // 首次加载
      loadOptions(undefined, undefined, searchData)
      // 判断是否需要回显
      if (value.model && value.modelField) {
        // 回显方法
        let echo = (model, modelField, searchData) => {
          let params = {}
          params[modelField] = model
          if (searchData) {
            Object.assign(params, searchData)
          }
          api[url](params).then(res => {
            if (res) {
              optionsCopy = optionsCopy.concat(res.data.data)
              dataProcessing(optionsCopy)
            }
          })
        }
        if (optionsCopy.length > 0) {
          let check = optionsCopy.find((item) => {
            return item[value.modelField] === value.model
          })
          if (!check) {
            echo(value.model, value.modelField, searchData)
          }
        } else {
          echo(value.model, value.modelField, searchData)
        }
      }
      // 滚动监听(无限滚动)
      el.querySelector('.el-select-dropdown .el-select-dropdown__wrap').addEventListener('scroll', function() {
        const condition = this.scrollHeight - this.scrollTop <= this.clientHeight + 100
        if (!timer && condition) {
          // 滚动加载
          loadOptions(searchField, searchValue, searchData)
          timer = setTimeout(() => {
            clearTimeout(timer)
            timer = null
          }, 200)
        }
      })
      // 输入监听(远程搜索)
      if (searchField) {
        const elInput = el.getElementsByTagName('input')[0]
        // 输入搜索
        elInput.addEventListener('input', function() {
          if (this.value) {
            searchPageNo = 1
            searchPages = 1
            optionsSearch = []
            searchValue = this.value
            loadOptions(searchField, searchValue, searchData)
          } else {
            searchValue = ''
            dataProcessing(optionsCopy)
          }
        })
        // 失去焦点时清除输入内容
        elInput.addEventListener('blur', function() {
          searchValue = ''
          dataProcessing(optionsCopy)
        })
      }
    }
  }
})

2. 在main中注

import directives from './directives'
Vue.use(directives)

3.使用方法 (我是有很多地方使用到,所以封装成组件)

3.1 方法一 

<template>
  <el-form-item className="areaSelect" label="采集器" prop="collectorIdValue">
    <el-select v-model="collectorIdValue" filterable :filter-method="()=>{}" remote :remote-method="remoteMethod" v-load-more.method="loadMore" style="width: 100%">
      <el-option ref="option" v-for="item in options" :key="item.value" :label="item.label" :value="item.value"></el-option>
    </el-select>
  </el-form-item>
</template>
data() {
  return {
    loading: false,
// 本来是想直接使用collectorId的,但是使用后报错,不允许我直接使用父传过来的,只好重新取一个
    collectorIdValue: '',
    options: [],
    params: {
      pageSize: 15,
      pageNum: 1,
      pageTotal: 0,
    },
  }
},
created() {
  this.remoteMethod()
},
props: {
  // 父传子的绑定数据
  collectorId: {
    default: null,
    type: [Number, String]
  },
},
watch: {
  // 监听绑定数据是否存在,存在则传递给父组件对应的数据
  'collectorIdValue': {
    handler(newVal) {
      if (newVal) {
        this.$parent.model.collectorId = newVal;
      } else {
        this.$parent.model.collectorId = ''
      }
    },
    immediate: true
  }
},
methods: {
  //  初始加载数据 
  remoteMethod(query) {
    this.loading = true;
    this.collectorIdValue = query || ''
    this.params.pageNum = 1
    const params = {
      pageSize: this.params.pageSize,
      pageNum: this.params.pageNum,
      collectorId: this.collectorIdValue
    }
    // 调用接口
    listCollector(params).then(response => {
      this.options = response.rows.map(el => {
        el.value = el.collectorId
        el.label = el.collectorId + '-(' + el.meterCount + ')只' + `${el.description? '-' + el.description : ''}`
        return el
      })
      this.params.pageTotal = response.total;
      this.loading = false;
    });
  },
  // 滚动到底部,加载数据
  loadMore(){
    if (this.options.length >= this.params.pageTotal) return
    this.params.pageNum++
    this.loading = true;
    const params = {
      pageSize: this.params.pageSize,
      pageNum: this.params.pageNum,
      collectorId: this.collectorIdValue
    }
    listCollector(params).then(response => {
      this.$nextTick(() => {
        this.options = this.options.concat(response.rows.map(el => {
          el.value = el.collectorId
          el.label = el.collectorId + '--(' + el.meterCount + ')只'
          return el
        }))
      })
      this.params.pageTotal = response.total;
      this.loading = false;
    });
  }
}

效果图:

3.2 方法二

<el-select v-model="id"
           filterable
           :filter-method="()=>{}"
           v-load-more="{
             url:'url',
             options: options,
             model: id,
             modelField: 'id',
             searchField: 'name'}"
           style="width: 100%">
  <el-option
    v-for="item in options"
    :key="item.id"
    :label="item.name"
    :value="item.id">
  </el-option>
</el-select>
 
data() {
  return {
    options:[],
    id: ''
  }

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用\[1\]和\[2\]提到了使用this.$forceUpdate()来重新渲染el-select组件。这个方法可以在数据赋值后手动调用,强制组件重新渲染。在el-select组件上添加key属性,将其绑定到一个会动态变化的值上,比如后端返回的数据集合的长度,也可以解决样式不一致的问题。所以,如果在element-ui使用el-select绑定函数时出现样式问题,可以尝试使用this.$forceUpdate()方法重新渲染组件,并在el-select上添加key属性绑定一个动态变化的值。 #### 引用[.reference_title] - *1* [element-ui 解决 el-select 设置默认值后无法切换选项](https://blog.csdn.net/weixin_44640323/article/details/122175514)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [element-ui 解决 el-select 设置初始默认值后切换选项无效问题](https://blog.csdn.net/sea9528/article/details/121403975)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [< element-UI el-select组件,下拉时内容无法显示滚动条 >](https://blog.csdn.net/MrWen2395772383/article/details/126159719)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值