#说明

代码中使用到了mobx,其实如果只要部分功能,可以不使用mobx,但主要此处列出可以有借鉴效果

一、调用

基本用法与正常antd的table一摸一样,只是多了几个个性化属性,可以满足个性化需求

```jsx import React, { FC, useEffect } from ‘react’; import { observer } from ‘mobx-react’; import Store from ‘../store’; import { Table } from ‘antd’; import columns from ‘./columns’; import style from ‘../style.scss’; import { MyEmpty,MyTable } from ‘~/components’;

interface IProps { store: Store; }

const PageTable: FC = (props) => { const { source: { tableList, pageConfig, loading }, getTableList, handleChangeTable, } = props.store; useEffect(() => { getTableList(); }, []);

return (

, //此处调用的是,如果为空组件 }} />
); }; export default (PageTable); <a name="121520f9"></a> # 二、运行效果 > ![](AntDesignOfReact%E5%B0%81%E8%A3%85%E7%BB%84%E4%BB%B6%E4%B8%AD%E7%9A%84%E5%9B%BE%E7%89%87/image-20210806184129571.png#alt=) <a name="2b279f6d"></a> # 三、封装 <a name="d8de4eb1"></a> ## Ⅰ-SCSS文件 >scss //table.scss .tableWrapper { :global { .ant-table-row-expand-icon { &::before { top: 7px !important; right: 2px !important; left: 3px !important; height: 2px !important; } &::after { top: 3px !important; bottom: 2px !important; left: 7px !important; width: 2px !important; } } .react-resizable { position: relative; background-clip: padding-box; } .react-resizable-handle { position: absolute; right: 0px; bottom: 0; z-index: 1; width: 5px; height: 100%; cursor: col-resize; } } } .filterBody { width: 240px; .filterTitle { padding: 8px 32px; } .filterItem { padding: 0px 15px; width: 100%; height: 100%; display: flex; align-items: center; justify-content: space-between; cursor: pointer; color: #353535; .filterText { height: 30px; line-height: 30px; } &.cursorItem { cursor: not-allowed; } } .filterItem:hover { background: #f1f1f1; color: rgba(53, 105, 253, 1); border-radius: 2px; } .line { width: 18px; height: 1px; background-color: #e8e8e8; margin: 10px 16px; } } <a name="777afb7c"></a> ## Ⅱ-resizable-title.tsx > 此处为可拖拽表格组件 >jsx import React, { useLayoutEffect, useRef } from ‘react’; import { Resizable } from ‘react-resizable’; const ResizableTitle = (props) => { const { onResize, width, …restProps } = props; const thRef = useRef(); return ( { e.stopPropagation(); }} /> } onResize={onResize} draggableOpts={{ enableUserSelectHack: false }} > ); }; export default ResizableTitle; <a name="5183b662"></a> ## Ⅲ-table.tsx >jsx import React, { useCallback, useEffect, useMemo, useRef, useState, } from ‘react’; import { Table, TableProps } from ‘antd’; import { CheckOutlined } from ‘@ant-design/icons’; import { inject, observer } from ‘mobx-react’; import style from ‘./table.scss’; import ResizableTitle from ‘./resizable-title’; import { ColumnsType } from ‘antd/lib/table’; interface SuperTableProps extends TableProps { showId?: boolean; //是否显示筛选自定义列表图标 showColumnFilter?: boolean; menuStore?: any; userStore?: any; //首列ID是否浮动定位,传入为字符串类型,不传则为空不浮动 fixedType?: String | undefined; //首列ID列的宽度 idWidth?: Number | undefined; //是否需要默认渲染ID列—>true:隐藏 hidderIDColumns?: boolean; } function MyTable( props: SuperTableProps ) { const TABLECONFIG_KEY = `TABLE_COLUMNS_CONFIGS${props.userStore.user.name}`; const { showColumnFilter = true } = props; const [hiddenColumns, setHiddenColumns] = useState([]); const [columns, setColumns] = useState([]); const [sorterColumn, setSorterColumn] = useState(); const handleResizeRef = useRef(); const [pagiConfig, setPagiConfig] = useState({}); useEffect(() => { /* 初次进入页面时,从 localStorage 中读取数据,初始化 hiddenColumns */ const oldTableColumnsConfigs = JSON.parse( localStorage.getItem(TABLE_CONFIG_KEY) ); if (!oldTableColumnsConfigs) { return; } const oldHiddenColumns = oldTableColumnsConfigs[props.menuStore.activeKey]; if (oldHiddenColumns) { setHiddenColumns(oldHiddenColumns); } }, [props.menuStore.activeKey, setHiddenColumns]); handleResizeRef.current = (index) => (e, { size }) => { const nextColumns = […columns]; nextColumns[index] = { …nextColumns[index], width: size.width, }; setColumns(nextColumns); }; useEffect(() => { const { pagination = {}, filters, sorter, otherParams } = pagiConfig; if (pagination?.current > 1 && props?.dataSource?.length === 0) { // 删除了最后一条数据应该返回上一页 let newPagi = { …pagination, current: pagination.current - 1, }; handleTableChange(newPagi, filters, sorter, …otherParams); } }, [props?.dataSource?.length]); useEffect(() => { const { showId = true } = props; let newColumns = props.columns || React.Children.map(props.children, (child: any) => child?.props); const hasIdField = newColumns.some( (col) => col.dataIndex?.toLowerCase() === ‘id’ ); if (!hasIdField && showId) { //不传或者传入为false时,为不隐藏ID列 if (!props?.hidderIDColumns) newColumns.unshift({ title: ‘ID’, dataIndex: ‘id’, //首列id宽度,如果不传入则默认150 width: props?.idWidth || 150, //首列ID是否浮动定位,传入为字符串类型,不传则为空 fixed: props?.fixedType, }); } newColumns = newColumns.map((col, index) => ({ …col, onHeaderCell: (column) => ({ width: column.width, onResize: handleResizeRef.current(index), }), })); setColumns(newColumns); }, [props.columns, props.children, handleResizeRef]); const filteredColumns = useMemo(() => { //此处根据传入数组 function applySorterToColumns(columns: ColumnsType) { return columns.map((item) => { if (‘sorter’ in item) { return { …item, key: item.key || item.dataIndex, sortOrder: sorterColumn?.field == item.dataIndex && sorterColumn?.order, }; } return { …item, key: item.key || item.dataIndex, isCustomSorter: true, // sorter: (a, b) => { // return a[item.dataIndex] - b[item.dataIndex]; // }, // sortOrder: // sorterColumn?.field == item.dataIndex && sorterColumn?.order, }; }); } const filterColumns = columns.filter( (columns) => !hiddenColumns.includes(columns.dataIndex) ); const lastColumn = filterColumns[filterColumns.length - 1]; filterColumns[filterColumns.length - 1] = { …lastColumn, filterDropdown: showColumnFilter ? (…params) => { if (lastColumn.filterDropdown) { return lastColumn.filterDropdown(…params); } else { return filterDropdown(…params); } } : undefined, }; //此行控制列表为部筛选图标 return applySorterToColumns(filterColumns); }, [columns, hiddenColumns, sorterColumn]); function setTableField(dataIndex) { let newHiddenColumns = […hiddenColumns]; if (hiddenColumns.includes(dataIndex)) { newHiddenColumns = hiddenColumns.filter((item) => item !== dataIndex); } else { newHiddenColumns = […hiddenColumns, dataIndex]; } //判断是否赋值 if ( columns.some((value) => value.title == ‘操作’) && columns.length - 1 == newHiddenColumns.length ) { return; } if (columns.length == newHiddenColumns.length) { return; } setHiddenColumns(newHiddenColumns); if (!localStorage.getItem(TABLE_CONFIG_KEY)) { localStorage.setItem( TABLE_CONFIG_KEY, JSON.stringify({ [props.menuStore.activeKey]: newHiddenColumns, }) ); } else { const oldTableColumnsConfigs = JSON.parse( localStorage.getItem(TABLE_CONFIG_KEY) ); localStorage.setItem( TABLE_CONFIG_KEY, JSON.stringify({ …oldTableColumnsConfigs, [props.menuStore.activeKey]: newHiddenColumns, }) ); } } function filterDropdown(…params) { return (
自定义表格字段
  1. {columns?.map((column, index) => {
  2. //不将`操作`放入自定义下拉框中--->暂时将最后一列隐藏,后续再改
  3. if (columns?.length - 1 != index || column?.title != '操作')
  4. return (
  5. <div
  6. key={index}
  7. className={style.filterItem}
  8. onClick={() => setTableField(column.dataIndex)}
  9. >
  10. <div className={style.filterText}>{column.title}</div>
  11. {!hiddenColumns.includes(column.dataIndex) && <CheckOutlined />}
  12. </div>
  13. );
  14. })}
  15. </div>

); }

function handleTableChange(pagination, filters, sorter, …otherParams) { setPagiConfig({ pagination, filters, sorter, otherParams }); console.log(sorter, ‘sorter’);

setSorterColumn({ field: sorter?.field, order: sorter?.order });

/**

  1. * 前端排序的字段,在 onChange 时清空 sorter
  2. * 避免外部捕获 sorter 后传给接口报错
  3. */

if (sorter?.column?.isCustomSorter) { sorter.field = ‘’; sorter.order = ‘’; }

if (props.onChange) { props.onChange(pagination, filters, sorter, …otherParams); } } // debugger return (

); }

export default inject(‘menuStore’, ‘userStore’)(observer(MyTable)); ```