react+antd封装表格组件2.0
- 1.0版本 仅仅封装组件,不涉及方法
- 需要掌握知识点
- useImperativeHandle
- 组件代码
- 引用
1.0版本 仅仅封装组件,不涉及方法
1.0 仅封装组件
此方法把所用方法集体封装,以后就可以无脑开发拉!
- 只需传入路径,组件列表请求、增删改后更新属性均在组件内发生
- 当前页不是第一页且删除后无数据,则自动跳转到上一页
- 查询时防止多次点击,点击一次后加遮罩,数据返回后放开
- 已有查询条件时,再次分页带上查询条件
需要掌握知识点
useImperativeHandle
一个用于暴露自定义ref属性和自定义方法的钩子函数。可以使得父组件可以通过ref访问子组件中定义的方法和属性,从而实现对子组件的精细控制
!!使用useImperativeHandle时必须与forwardRef搭配使用,否则会报错
- 具体使用步骤如下
//在子组件中定义需要暴露给父组件的方法和属性,并将这些方法和属性放在一个对象中
import { useImperativeHandle, forwardRef } from 'react';const Child = forwardRef((props, ref) => {const [count, setCount] = useState(0);const increment = () => {setCount(count + 1);};// 定义需要暴露给父组件的方法和属性useImperativeHandle(ref, () => ({increment,count,}));return <div>{count}</div>;
});
//在父组件中使用子组件,并给子组件传递一个ref属性,
import { useRef } from 'react';
import Child from './Child';const Parent = () => {// 创建一个refconst childRef = useRef();// 在父组件中通过ref访问子组件的方法和属性const handleClick = () => {childRef.current.increment();};return (<div><button onClick={handleClick}>Click me</button><Child ref={childRef} /></div>);
};
//父组件中的handleClick方法通过childRef.current访问了Child组件中的increment方法和count属性。
组件代码
import { Table, Pagination, Button, Dropdown, Checkbox, message } from 'antd';
import { useDispatch } from 'umi';
import { useState, useEffect, forwardRef, useImperativeHandle } from 'react';
import { PicRightOutlined } from '@ant-design/icons';import './index.less';const TableComponent = forwardRef((props, ref) => {const dispatch = useDispatch();const [open, setOpen] = useState(false); //动态控制列的下拉显隐const [items, setItems] = useState([]); //当前的下拉选择状态const [loading, setLoading] = useState(true); //当前的加载状态const [dataSource, setDataSource] = useState([]); //列表数据const [total, setTotal] = useState(0); //分页总数const [size, setSize] = useState(10); //分页页数const [current, setCurrent] = useState(1); //分页当前页// 抛出获取列表方法useImperativeHandle(ref, () => ({getList,}));// 表格列表const [columns, setColumns] = useState(props.columns.map((item) => {return {...item,align: 'center',ellipsis: {showTitle: false,},};}),);//控制列的初始值const [starCol, setStarCol] = useState(props.columns.map((item) => {return {...item,check: true,align: 'center',ellipsis: {showTitle: false,},};}),);useEffect(() => {changItem(starCol);}, [props]);useEffect(() => {if (props.columns || props.columns.length > 0) {setColumns(props.columns.map((item) => {return {...item,align: 'center',ellipsis: {showTitle: false,},};}),);setStarCol(props.columns.map((item) => {return {...item,check: true,align: 'center',ellipsis: {showTitle: false,},};}),);}}, [props.columns]);useEffect(() => {// 初始请求列表if (props.url) {getList();}}, [props.url]);useEffect(() => {// 新增编辑后列表刷新if (props.list) {const list = props.list?.map((item, index) => {return {index: serialNumber(current, size, index + 1),...item,};});setDataSource(list);}}, [props.list]);useEffect(() => {if (props.search) {dispatch({type: 'utils/searchLoadingEvent',payload: true,});// 搜索请求列表getList(1, size, props.search, true);}}, [props.search]); //监听列表传入查询条件const getList = (pageCurrent, pageSize, values, isClickSearch) => {if (!isClickSearch) {// 获取列表时 没点击查询按钮 加载列表setLoading(true);}const payload = {current: pageCurrent || current,size: pageSize || size,...values,};dispatch({type: props.url,payload: payload,callback: (res) => {if (res) {setTotal(res.total);setSize(res.size);setCurrent(res.current);const list = res.data?.map((item, index) => {return {index: serialNumber(res.current, res.size, index + 1),...item,};});setDataSource(list);setLoading(false);props.listPaginationChange(payload); //更新接口条件// 处理列表最后一条数据删除时请求上一页数据if (res.data?.length == 0 && res.total > 0) {getList(res.current - 1, res.size, props.search);}//点击查询按钮 获取到数据后 关闭局部加载if (isClickSearch) {dispatch({type: 'utils/searchLoadingEvent',payload: false,});}}},});};// 分页查询列表const paginationChange = (pageCurrent, pageSize) => {getList(pageCurrent, pageSize, props.search || null);};//这个方法可加可不加,是因为前端需要展示序号,而后端不返回,所以就自己计算啦!const serialNumber = (pageIndex, pageSize, index) => {return (pageIndex - 1) * pageSize + index;};// 控制显示列的操作const onClick = ({ key }) => {if (key == 'all') {const newDrop = starCol;newDrop.map((o, index) => {o.check = true;});changItem(starCol);setColumns(props.columns.map((item) => {return {...item,check: true,align: 'center',ellipsis: {showTitle: false,},};}),);} else {const newDrop = starCol;newDrop.map((o, index) => {if (index == key) {o.check = !o.check;}});let newColumns = newDrop.filter((o) => o.check);if (newColumns.length == 0) {message.warning('请至少选择一列');} else {setStarCol(newDrop);changItem(newDrop);setColumns(newColumns); //列状态}}};// 列的选中状态改变const changItem = (data) => {let opitems = data.map((item, index) => {return {key: index,label: <Checkbox checked={item.check}>{item.title}</Checkbox>,};});opitems.unshift({key: 'all',label: <Button>{'全选列'}</Button>,},{type: 'divider',},);setItems(opitems); //当前的下拉状态};return (<div className="table">{!props?.selectIf && (<Dropdownmenu={{items,onClick,}}overlayClassName="drop"trigger={['click']}onOpenChange={() => setOpen(!open)}open={open}arrowplacement="bottomRight"><a onClick={(e) => e.preventDefault()}><Button icon={<PicRightOutlined />} title="显示/隐藏列"></Button></a></Dropdown>)}<Tableborderedcolumns={columns}rowSelection={props?.rowSelection}// dataSource={isShow ? dataSource : null}dataSource={dataSource}rowKey={(item) => item.id || item.categoryId || item.modelId}pagination={false}className="insiadeTable"scroll={{y: 450,...props?.scroll,}}onRow={props?.onRow}rowClassName={props?.rowClassName}summary={props?.summary}loading={loading}/><div className="pagination"><PaginationshowQuickJumperdefaultCurrent={current}total={total}showTotal={(total) => `共 ${total} 条`}size={size}current={current}onChange={paginationChange}pageSizeOptions={[10, 50, 100, 500]}/></div></div>);
});export default TableComponent;
引用
···const [search, setSearch] = useState(null); //搜索条件const tableComponentRef = useRef(null);const list = useSelector((state) =>state.roleManagement.roleManagementList);const [search, setSearch] = useState(null);const [listChange, setListChange] = useState(list);const [listPaginationChange, setListPaginationChange] = useState(null);
···useEffect(() => {if (list) {setListChange(list); //组件内数据响应后此处更新}}, [list]);
···const onFinish = (values) => {setSearch(values); //点击搜索后设置值};···<Form onFinish={onFinish} form={form} requiredMark={'Hidden'}><Row gutter={16}><Col span={6}><Form.Itemname="keyword"label="关键字"><Input allowClear /></Form.Item></Col><Col span={4}><Space><Buttontype="primary"icon={<SearchOutlined />}htmlType="submit">搜索</Button><Buttonicon={<SyncOutlined />}onClick={() => {form.resetFields();}}>重置</Button></Space></Col></Row></Form><TableComponentref={tableComponentRef} //组件实例url="roleManagement/getRoleManagementList"search={search} //搜索条件list={listChange} //数据源listPaginationChange={(e) => {//{current:1,size:10,..查询条件} 格式setListPaginationChange(e);}}className="list"columns={columns} //列scroll={{x: 1600,}}/>
- 新增修改组件
<EditfillingForm={fillingForm}open={isModalOpen}setIsModalOpen={setIsModalOpen}//修改新增组件只需传入listPaginationChange,便可保留分页及查询条件listPaginationChange={listPaginationChange}/>//修改新增后调用即可 const getRoleList = () => {dispatch({type: 'roleManagement/getRoleManagementList',payload: props.listPaginationChange,};