基于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>