antd vue二次封装远程搜索下拉框组件,支持滚动分页

本文介绍了如何在Vue2项目中使用antdvueUI库对下拉框组件进行二次封装,实现远程搜索、滚动分页、单选/多选功能,并包含防抖处理和数据加载控制。
摘要由CSDN通过智能技术生成

vue2中使用antd vueUI 二次封装远程搜索下拉框组件,支持滚动分页,单选和多选,最多选择数量限制,滚动获取数据防抖

具体组件代码如下

<template>
  <a-select
    :disabled="disabled"
    :mode="mode"
    :maxTagCount="maxTagCount"
    show-search
    allowClear
    :filterOption="false"
    :label-in-value="labelInValue"
    :placeholder="placeholderStr"
    style="width: 100%"
    :not-found-content="fetching ? undefined : notFoundContent"
    @search="handleSearch1"
    @change="handleChange"
    @popupScroll="popupScroll1"
    :value="selectValue"
    :getPopupContainer="(node) => node.parentNode"
  >
    <a-select-option
      v-for="item in dataOptions"
      :disabled="item.disabled"
      :key="item.id"
      :value="item[optionValueKey]"
      >{{ item[optionLabelKey] }}</a-select-option
    >

    <a-select-option :disabled="true" key="loading"
      ><a-spin :spinning="fetching">
        <div style="height: 20px; text-align: center">
          {{
            dataOptions.length == 0
              ? notFoundContent
              : noMoreData
              ? '已经到底了~'
              : '加载中'
          }}
        </div>
      </a-spin></a-select-option
    >
  </a-select>
</template>

<script>
import debounce from 'lodash/debounce';
export default {
  name: 'RemoteSelect',
  props: {
    mode: {
      type: String,
      default: 'default',
    },
    labelInValue: { type: Boolean, default: false },
    maxTagCount: Number,
    maxLimit: Number, //多选时,最大数量
    placeholderStr: {
      type: String,
      default: '请输入',
    },
    url: String,
    defaultValue: { type: [Array, String, Number], default: '' }, //初始值
    params: {
      type: Object,
      default: () => ({}),
    }, //调用接口的入参字段
    searchKey: { type: String, default: 'name' }, //搜索的字段
    returnParams: { type: Object, default: () => ({}) }, //调用接口的返回参数
    optionValueKey: { type: String, default: 'id' }, //option下拉选项的value用哪个字段
    optionLabelKey: { type: String, default: 'name' }, //option下拉选项的显示用哪个字段
    method: {
      type: String,
      default: 'post',
    },
    showSearch: {
      type: Boolean,
      default: true,
    },
    optionFilterProp: {
      type: String,
      default: 'value',
    },
    notFoundContent: {
      type: String,
      default: '暂无查询数据',
    },
    pageSize: {
      type: Number,
      default: 50,
    },
    disabled: {
      type: Boolean,
      default: false,
    },
    // 是否默认选择第一条数据
    firstItemSelected: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    this.handleSearch1 = debounce(this.handleSearch, 100);
    this.popupScroll1 = debounce(this.popupScroll, 100);
    return {
      dataOptions: [],
      fetching: false,
      currentPage: 1,
      noMoreData: false,
      searchValue: '',
      selectValue: !this.defaultValue ? undefined : this.defaultValue,
      total: 0,
    };
  },
  mounted() {
    this.handleSearch();
  },
  watch: {
    defaultValue: {
      handler(newVal, oldVal) {
        this.handleChange(newVal);
      },
    },
  },
  methods: {
    async handleSearch(value) {
      if (this.fetching == true) return;
      this.searchValue = value;
      this.currentPage = 1;
      this.noMoreData = false;
      this.fetchData(value);
    },
    //处理选择的上限处理逻辑
    initSelectOptions() {
      if (
        this.maxLimit &&
        this.selectValue &&
        this.selectValue.length >= this.maxLimit
      ) {
        if (!this.labelInValue) {
          this.dataOptions.forEach((element) => {
            if (!this.selectValue.includes(element[this.optionValueKey])) {
              element.disabled = true;
            }
          });
        }
      } else {
        this.dataOptions.forEach((element) => {
          element.disabled = false;
        });
      }
    },
    async handleChange(value) {
      this.initSelectOptions();
      const { onChange } = this;
      this.selectValue = value;
      console.log('selectValue', this.selectValue);
      if (this.input) {
        this.$emit('input', value);
      }
      this.$emit('onChange', value);

      if (value == undefined) {
        //清除选择项时,需要重新获取下拉框数据
        this.handleSearch();
      }
    },
    async fetchData(value) {
      if (this.fetching == true) return;
      const { url, params, pageSize } = this;
      console.log('params', params);
      this.fetching = true;
      const res = await this.$request.post(url, {
        pageIndex: this.currentPage,
        pageSize: pageSize,
        [this.searchKey]: value,
        ...params,
      });

      if (res.data.status == 200) {
        const { models, sum } = res.data && res.data.data;
        this.total = sum;
        if (this.currentPage === 1) {
          this.$set(this, 'dataOptions', models);
        } else {
          this.dataOptions = [...this.dataOptions, ...models];
        }
        //默认选择第一条数据
        if (this.firstItemSelected && this.dataOptions.length > 0) {
          this.handleChange(this.dataOptions[0][this.optionValueKey]);
        }
        if (sum <= this.dataOptions.length) {
          this.noMoreData = true;
        }
      } else {
        //接口报错
        this.noMoreData = true;
      }
      this.fetching = false;
    },
    popupScroll(e) {
      const { scrollTop, scrollHeight, clientHeight } = e.target;
      if (
        !this.noMoreData &&
        !this.fetching &&
        scrollTop + clientHeight >= scrollHeight - 100
      ) {
        this.currentPage++;
        this.fetchData(this.searchValue);
      }
    },
  },
};
</script>

  • 9
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值