react hook antd5.x解决table列宽大小问题

由于项目多处使用到了table,所以这边我进行了封装,这边使用了react-resizable模块

1.第一步 安装模块

        安装模块:npm install react-resizable -save

2.第二步 封装组件

        handleResize.tsx 是用于改变列宽的width的值

/src/components/handleResize/handleResize.tsx

function handleResize(
  col: { key?: any, width?: any },
  size: { width: any },
  oldColumn: any,
  setColumn: Function,
) {
  const newColumns = [...oldColumn];
  newColumns.forEach((item) => {
    if (item.key === col.key) {
      item.width = size.width;
    }
  });

  setColumn(newColumns);
}
export default handleResize;

        ResuzeableTitle.tsx

src/components/ResizeableTitle/ResizeableTitle.tsx

import { Resizable } from 'react-resizable';

function ResizableTitle(props: {
  [x: string]: any;
  onResize: any;
  className: any;
  width?: number;
  title: any;
  children: any;
}) {
  const {
    onResize,
    className,
    width,
    title,
    children,
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    ...restProps
  } = props;
  // const _ = require('lodash');
  // ! 让antd的样式和resizable的样式共存
  // const sty = _.merge(props, restProps);
  return (
    <Resizable width={width ?? 90} height={0} onResize={onResize}> //这边我设置了默认的列表宽度为90
      <th>{children}</th>
      {/* <th {...sty}>{children}</th> */}
    </Resizable>
  );
}
export default ResizableTitle;

        StyledTable.tsx

/src/components/StyledTable/StyledTable.tsx

import React, { useMemo } from 'react';
import { Table } from 'antd';
import styled from 'styled-components';
import { TableProps } from 'antd/lib/table';
// import { PaginationConfig } from 'antd/lib/pagination';
import handleResize from '../handleResize/handleResize';

interface FTableProps<T> extends TableProps<T> {
  editingKey?: string | number;
  highlightRow?: object;
  rowKey?: string | ((record: T, index?: number) => string);
  onSaveRowEdit?: (record: T, data: object[]) => void;
  onCancelRowEdit?: (record: T) => void;
  onRowEditing?: (record: T) => void;
  afterRowDrag?: (record: T) => void;
  dragable?: boolean;
  editRow?: boolean;
}

//由于我这边使用的表格和官网的表格样式有些不一致,所以这边用styled更改了原生的表格样式
const StyledTableWrapper = styled(Table)`
  & .itsm-spin-nested-loading, & .itsm-spin-container {
    height: 100% !important;
  }
  & .itsm-spin-container{
    display: flex;
    flex-direction: column;
  }
  & .itsm-table{
    flex-grow: 1;
    overflow: auto;
    color: #fff;
    background: none;
  }
  & .itsm-table-thead > tr > th,
  .itsm-table-tbody > tr > td,
  .itsm-table tfoot > tr > th,
  .itsm-table tfoot > tr > td {
    padding: 0 !important;
    padding-left:14px !important;
  }
  & .itsm-table {
    font-size: 14px !important;
    line-height: 40px !important;
  }
  & .itsm-table-tbody > tr > td {
    border-bottom: none !important;
  }
  & .itsm-table-thead > tr > th{
    background: rgba(26, 78, 124, 0.2) !important;
    color: #fff;
    border-bottom: none !important;
  }
  & td.itsm-table-cell.itsm-table-cell-fix-right.itsm-table-cell-fix-right-first{
    padding-left:0 !important;
  }
  & .itsm-table-cell-fix-left, .itsm-table-cell-fix-right{
    background: none;
  }
  & .itsm-table-tbody > tr.itsm-table-row:hover > td, .itsm-table-tbody > tr > td.itsm-table-cell-row-hover{
    background: #1d3058;
  }
  & .itsm-pagination-item-active{
    background-color: #048CB6;
    border-radius: 4px;
  }
  & .itsm-pagination-item a{
    color:#fff;
  }
  & .itsm-pagination-options-quick-jumper input{
    background-color: transparent;
    border: 1px solid #048cb6;
    border-radius: 4px;
    color:#fff
  }
  & span.itsm-pagination-item-ellipsis{
    color: #fff !important;
  }
  // & .anticon svg{
  //   color:#fff;
  // }
  & .itsm-select:not(.itsm-select-customize-input) .itsm-select-selector{
    background-color: transparent;
    border: 1px solid #048cb6;
    border-radius: 4px;
  }
  & .itsm-select{
    color:#fff;
  }
  & .itsm-table-empty .itsm-table-tbody > tr.itsm-table-placeholder, .itsm-empty-normal{
    color:#fff;
  }
  & .itsm-table-tbody > tr.itsm-table-placeholder:hover > td{
    background:transparent;
  }
  & .itsm-table-tbody > tr.itsm-table-row-selected > td{
    background-color: transparent;
  }
`;

interface StyledTableProps<T> extends FTableProps<T> {
  hideEmptyColumns?: string[];
}

function StyledTable<T>({ columns, hideEmptyColumns, ...props }: StyledTableProps<T>) {
  const pagination = useMemo(() => { //表格下面的页面
    const mPagination = {
      showTotal: (total: any, range: any[]) => `共有${total}条`,
      size: 'small',
      showSizeChanger: true,
      showQuickJumper: true,
      pageSizeOptions: [5, 10, 15, 20],
      style: { marginRight: '20px', fontSize: '14px', marginTop: '20px', color: '#fff' },
    };
    if (props.pagination) {
      return mPagination;
    }
    return mPagination;
  }, [props.pagination]);

  const customColumns = useMemo(() => {
    if (!hideEmptyColumns || !hideEmptyColumns.length) {
      return columns;
    }
    const dataList = props.dataSource;
    if (!columns || !dataList) {
      return columns;
    }
    const newColumns = [...columns];
    newColumns.map((it) => ({
      ...it,
      ellipsis: {
        showTitle: true,
      },
      onHeaderCell: (col: { width?: any; key?: any; }) => ({
        width: col.width,
        // !传入newColumn,而不传入column是因为需要拿到有onHeaderCell的值,外面collumn的变化内部监听不到
        onResize: (_e: any, { size }: any) => handleResize(col, size, newColumns, Function),
      }),
    }));
    return newColumns;
  }, [columns, hideEmptyColumns, props.dataSource]);
  // @ts-ignore
  return <StyledTableWrapper className="svgColor" bordered={props.bordered ?? false} pagination={pagination} {...props} columns={customColumns as any[]} />;
}

export default StyledTable;

3.第三步 使用Table表格

        注意:如果表格在收缩列宽的时候,页面发生抖动的请求,请检查自己的key的值有没有填写,如果不想修改,请将handleResize.tsx里面的key修改成你所写的键名

        注意:这边的columns不能写width值,因为会有冲突出现

/src/pages/Home/index.tsx

import ResizableTitle from '../../../components/ResizeableTitle/ResizeableTitle';
import handleResize from '../../../components/handleResize/handleResize';
import StyledTable from '../../../components/StyledTable/StyledTable';
import { useEffect, useMemo, useState } from 'react';


function Home() {
  const columns = useMemo(() => {
    const list: any = [
      {
        title: '单号',
        dataIndex: 'No',
        key: 'No',
      },
      {
        title: '标题',
        dataIndex: 'Title',
        ellipsis: true,
        key: 'Title',
      },
      {
        title: '创建时间',
        dataIndex: 'createTime',
        key: 'createTime',
        ellipsis: true,
      },
    ];
    return list;
  }, []);
  
  const [column, setColumn] = useState(columns);

  useEffect(() => {
    const newColumn = [...column].map((it) => ({
      ...it,
      ellipsis: {
        showTitle: true,
      },
      onHeaderCell: (col: { width?: any; key?: any; }) => ({
        width: col.width,
        // !传入newColumn,而不传入column是因为需要拿到有onHeaderCell的值,外面collumn的变化内部监听不到
        onResize: (_e: any, { size }: any) => handleResize(col, size, newColumn, setColumn),
      }),
    }));
    setColumn(newColumn);
  }, [column]);

  return (
    <div>
      <StyledTable
        dataSource={[
          { No: '01', Title: '张三', createTime: '2022-01-01' },
          { No: '02', Title: '李四', createTime: '2022-01-01' },
          { No: '03', Title: '王二五', createTime: '2022-01-01' },
        ]}
        rowKey="id"
        style={{ flexGrow: 1, overflow: 'hidden' }}
        rowClassName={(_record, index: number) => {
          let className = '';
          className = index % 2 === 0 ? 'oddRow' : 'evenRow';
          return className;
        }}
        columns={column}
        components={{
          header: {
            cell: ResizableTitle,
          },
        }}
      />
    </div>
  );
}
export default Home;

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的可编辑表格的示例代码,使用React HookAntd组件库: ```javascript import React, { useState } from 'react'; import { Table, Input, InputNumber, Popconfirm, Form } from 'antd'; const EditableCell = ({ editing, dataIndex, title, inputType, record, index, children, ...restProps }) => { const inputNode = inputType === 'number' ? <InputNumber /> : <Input />; return ( <td {...restProps}> {editing ? ( <Form.Item name={dataIndex} style={{ margin: 0 }} rules={[ { required: true, message: `Please Input ${title}!`, }, ]} > {inputNode} </Form.Item> ) : ( children )} </td> ); }; const EditableTable = () => { const [form] = Form.useForm(); const [data, setData] = useState([ { key: '1', name: 'John Brown', age: 32, address: 'New York No. 1 Lake Park', }, { key: '2', name: 'Joe Black', age: 42, address: 'London No. 1 Lake Park', }, { key: '3', name: 'Jim Green', age: 32, address: 'Sidney No. 1 Lake Park', }, { key: '4', name: 'Jim Red', age: 32, address: 'London No. 2 Lake Park', }, ]); const [editingKey, setEditingKey] = useState(''); const isEditing = (record) => record.key === editingKey; const edit = (record) => { form.setFieldsValue({ name: '', age: '', address: '', ...record, }); setEditingKey(record.key); }; const cancel = () => { setEditingKey(''); }; const save = async (key) => { try { const row = await form.validateFields(); const newData = [...data]; const index = newData.findIndex((item) => key === item.key); if (index > -1) { const item = newData[index]; newData.splice(index, 1, { ...item, ...row }); setData(newData); setEditingKey(''); } else { newData.push(row); setData(newData); setEditingKey(''); } } catch (errInfo) { console.log('Validate Failed:', errInfo); } }; const columns = [ { title: 'Name', dataIndex: 'name', width: '25%', editable: true, }, { title: 'Age', dataIndex: 'age', width: '15%', editable: true, }, { title: 'Address', dataIndex: 'address', width: '40%', editable: true, }, { title: 'Action', dataIndex: 'action', render: (_, record) => { const editable = isEditing(record); return editable ? ( <span> <a href="javascript:;" onClick={() => save(record.key)} style={{ marginRight: 8 }} > Save </a> <Popconfirm title="Sure to cancel?" onConfirm={cancel}> <a>Cancel</a> </Popconfirm> </span> ) : ( <a disabled={editingKey !== ''} onClick={() => edit(record)}> Edit </a> ); }, }, ]; const mergedColumns = columns.map((col) => { if (!col.editable) { return col; } return { ...col, onCell: (record) => ({ record, inputType: col.dataIndex === 'age' ? 'number' : 'text', dataIndex: col.dataIndex, title: col.title, editing: isEditing(record), }), }; }); return ( <Form form={form} component={false}> <Table components={{ body: { cell: EditableCell, }, }} bordered dataSource={data} columns={mergedColumns} rowClassName="editable-row" pagination={{ onChange: cancel, }} /> </Form> ); }; export default EditableTable; ``` 这个表格组件的主要思路是: 1. 使用`useState` Hook来保存表格数据和当前正在编辑的行的key。 2. 创建一个可编辑的单元格组件`EditableCell`,根据`editing`属性来展示编辑状态或者展示状态。当编辑状态时,渲染一个`antd`的`Form.Item`,提供一个可编辑的输入框。 3. 创建一个可编辑的表格组件`EditableTable`,渲染一个`antd`的`Table`组件。 4. 在表格的每一中添加一个`editable`属性,表示该是否可编辑。对于可编辑的,使用`onCell`属性指定可编辑单元格的属性。 5. 在渲染表格的每一行时,根据当前行是否处于编辑状态来决定展示编辑状态还是展示状态。如果处于编辑状态,则渲染可编辑的单元格,否则渲染非可编辑的单元格。 6. 在表格中添加编辑和保存按钮,点击编辑按钮时进入编辑状态,点击保存按钮时保存修改。同时,保存和取消操作会将当前行的编辑状态取消。 这样,我们就完成了一个简单的可编辑表格。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值