基于antd Select创建支持分页下拉的下拉框组件

基于antd Select创建支持分页下拉的下拉框组件

在工作的过程中,有些下拉框的数据非常大,需要前端传递分页参数进行后端请求,有时还需要进行支持搜索,所以抽离出这么一个组件是非常有必要的,那么话不多说直接上代码。

先看除antd-Select的入参

export interface propsTypes{
  // 后端获取数据的函数
  getListData: (e: any) => any
  // 处理下拉框搜索值的格式化
  onSearch?: (e: string) => any
}

兼容其他antd-Select的其他参数属性

具体组件的实现

import {useEffect, useState, forwardRef, useImperativeHandle} from "react";
import {Select, Spin, SelectProps} from "antd";
import {ListDataType, PropsTypes, PaginationType} from "./types";


const ViewMoreSelect = forwardRef((props: SelectProps & PropsTypes, ref) => {
  const { getListData, showSearch = false, onSearch, ...other } = props;
  const [loading, setLoading] = useState(false);
  const [listData, setListData] = useState<ListDataType[]>([]);
  const [searchData, setSearchData] = useState<any>({});
  const [pagination, setPagination] = useState<PaginationType>({
    total: 0,
    pageNo: 0,
    pageSize: 20
  });

  useImperativeHandle(ref, () =>( {
    // 提供一个外部调用重新请求的方法
    rQuery:() => {
      handleInit(searchData);
    },
    // 调用重置
    reset: () => {
      setListData([]);
      setSearchData({});
      setPagination({
        total: 0,
        pageNo: 0,
        pageSize: 20
      });
    }
  }));

  /**
   * 获取初始化数据
   */
  const handleInit = async (newSearchData?: any) => {
    const obj = {
      ...newSearchData,
      pageNo: 1,
      pageSize: 20
    };
    try {
      const res = await getListData(obj);
      if(res.data){
        setListData(res.data);
        setPagination({
          pageSize: 20,
          pageNo: 1,
          total: Number(res.total)
        });
      }
    }
    catch (err){
      console.log(err);
    }
  };

  /**
   * 动态请求数据
   */
  const fetchMoreData = async (newPagination: PaginationType, newListData: ListDataType[], newSearchData?: any) => {
    if (loading) return;
    setLoading(true);
    const obj = {
      ...newSearchData,
      pageNo: newPagination.pageNo + 1,
      pageSize: newPagination.pageSize
    };
    try {
      const res = await getListData(obj);
      if(res.data){
        setListData([...newListData, ...res.data]);
        setPagination({
          pageSize: newPagination.pageSize,
          pageNo: Number(res.pageNo),
          total: Number(res.total)
        });
        setLoading(false);
      }
    }
    catch (err){
      setLoading(false);
    }
  };

  /**
   * 下拉框滚动
   * @param e dom元素
   */
  const handleScroll = (e) => {
    const { target } = e;
    if (target.scrollTop + target.clientHeight + 1 >= target.scrollHeight) {
      if (pagination.total <= listData.length && listData.length > 0) return;
      fetchMoreData(pagination, listData, searchData);
    }
  };

  /**
   * 触发搜索
   * @param value
   */
  const handleOnSearch = async (value) => {
    if(typeof onSearch === 'function'){
      const result = onSearch(value);
      setSearchData(result);
      handleInit(result);
    }
  };

  useEffect(() => {
    handleInit(searchData);
  }, []);

  return(
    <Select
      allowClear
      onPopupScroll={handleScroll}
      loading={loading}
      {...(showSearch && {showSearch, onSearch: handleOnSearch, filterOption:false })}
      {...other}
    >
      {listData.map((item, index) => (
        <Select.Option key={index} value={item.value} {...item.option}>{item.label}</Select.Option>
      ))}
	  {/* 添加下拉时的loading */}
      {
        loading && <Select.Option disabled style={{textAlign: 'center'}} value={'loading'}>
          <Spin spinning={loading}/>
        </Select.Option>
      }
    </Select>
  );
});
export default ViewMoreSelect;

使用VieMoreSelect

在创建完组件后,使用就会显得非常简单,并且可以直接用 const [form] = Form.useForm();进行对下拉框进行数据操作

const getListData = async (obj: any) => {
  const res = await getPageData<PageDataType>(obj);
  if (res.data?.pageData) {
    return {
      data: res.data.pageData.records,
      pageNo: res.data.pageData.current,
      total: res.data.pageData.total
    };
  }
};

<Form.Item name="idList" label='label'>
	<ViewMoreSelect
	  ref={viewMoreSelectRef}
	  mode="multiple"
	  showSearch
	  onSearch={(value) => ({nameLike: value})}
	  getListData={getListData}
	  onChange={(value) => form.setFieldsValue({ idList: value })}
	/>
</Form.Item>
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值