react + antd 实现表格可拖拽列宽

本文介绍了如何在React和Ant Design中实现表格列宽的拖拽调整,分别演示了使用'react-resizable'库和'@minko-fe/use-antd-resizable-header'库的方法。前者在多列时可能出现卡顿,后者通过延迟调整避免了卡顿,提供了更好的用户体验。文中还提供了详细的代码示例,并讨论了两者的选择和注意事项。

react + antd 实现表格可拖拽列宽

前言: 接到一个需求,需要实现表格的表头可以拖拽调节宽度

实现方式

react-resizable GitHub

首先百度寻找解决方案,很容易的,我们就找到了react-resizable,这个解决方案在antd 3.x 的文档中,表格 Table - Ant Design,但是在更高的版本中没有,如果不是百度,我应该永远找不到.

安装
npm install --save react-resizable
使用

官方提供的代码示例:

import { Table } from 'antd';
import { Resizable } from 'react-resizable';

const ResizeableTitle = props => {
  const { onResize, width, ...restProps } = props;

  if (!width) {
    return <th {...restProps} />;
  }

  return (
    <Resizable
      width={width}
      height={0}
      onResize={onResize}
      draggableOpts={{ enableUserSelectHack: false }}
    >
      <th {...restProps} />
    </Resizable>
  );
};

class Demo extends React.Component {
  state = {
    columns: [
      {
        title: 'Date',
        dataIndex: 'date',
        width: 200,
      },
      {
        title: 'Amount',
        dataIndex: 'amount',
        width: 100,
      },
      {
        title: 'Type',
        dataIndex: 'type',
        width: 100,
      },
      {
        title: 'Note',
        dataIndex: 'note',
        width: 100,
      },
      {
        title: 'Action',
        key: 'action',
        render: () => <a>Delete</a>,
      },
    ],
  };

  components = {
    header: {
      cell: ResizeableTitle,
    },
  };

  data = [
    {
      key: 0,
      date: '2018-02-11',
      amount: 120,
      type: 'income',
      note: 'transfer',
    },
    {
      key: 1,
      date: '2018-03-11',
      amount: 243,
      type: 'income',
      note: 'transfer',
    },
    {
      key: 2,
      date: '2018-04-11',
      amount: 98,
      type: 'income',
      note: 'transfer',
    },
  ];

  handleResize = index => (e, { size }) => {
    this.setState(({ columns }) => {
      const nextColumns = [...columns];
      nextColumns[index] = {
        ...nextColumns[index],
        width: size.width,
      };
      return { columns: nextColumns };
    });
  };

  render() {
    const columns = this.state.columns.map((col, index) => ({
      ...col,
      onHeaderCell: column => ({
        width: column.width,
        onResize: this.handleResize(index),
      }),
    }));

    return <Table bordered components={this.components} columns={columns} dataSource={this.data} />;
  }
}

ReactDOM.render(<Demo />, mountNode);

css样式

#components-table-demo-resizable-column .react-resizable {
  position: relative;
  background-clip: padding-box;
}

#components-table-demo-resizable-column .react-resizable-handle {
  position: absolute;
  width: 10px;
  height: 100%;
  bottom: 0;
  right: -5px;
  cursor: col-resize;
  z-index: 1;
}

css样式需要添加到项目的全局配置中

示例是用class的方式写的,首先我要给他改成函数式组件的形式:

import { Table } from "antd";
import { useState } from "react";
import { Resizable } from 'react-resizable';

const ResizeableTitle = (props:any) => {
    const { onResize, width, ...restProps } = props;
  
    if (!width) {
      return <th {...restProps} />;
    }
  
    return (
      <Resizable
        width={width}
        height={0}
        onResize={onResize}
        draggableOpts={{ enableUserSelectHack: false }}
      >
        <th {...restProps} />
      </Resizable>
    );
  };

const initCols = [
    {
      title: 'Date',
      dataIndex: 'date',
      width: 200,
    },
    {
      title: 'Amount',
      dataIndex: 'amount',
      width: 100,
    },
    {
      title: 'Type',
      dataIndex: 'type',
      width: 100,
    },
    {
      title: 'Note',
      dataIndex: 'note',
      width: 100,
    },
    {
      title: 'Action',
      key: 'action',
      render: () => <a>Delete</a>,
    }
]

const TablePage:React.FC = () => {

    const [columns, setColumns] = useState(initCols);

    const data = [
        {
          key: 0,
          date: '2018-02-11',
          amount: 120,
          type: 'income',
          note: 'transfer',
        },
        {
          key: 1,
          date: '2018-03-11',
          amount: 243,
          type: 'income',
          note: 'transfer',
        },
        {
          key: 2,
          date: '2018-04-11',
          amount: 98,
          type: 'income',
          note: 'transfer',
        },
      ]

return <>
        <Table bordered dataSource={data}
         components={
             {
                 header: {
                     cell: ResizeableTitle
                 }
             }
         }
         columns={
            columns.map((col:any, index:number) => {
                return {
                    ...col,
                    onHeaderCell: (column:any) => ({
                        width: column.width,
                        onResize: (e:any, {size}:{size:any}) => {
                            setColumns((columns) => {
                                const nextColumns = [...columns];
                                nextColumns[index] = {
                                    ...nextColumns[index],
                                    width: size.width
                                }
                                return nextColumns;
                            })
                        }
                    })
                }
            })
        }>
        </Table>
    </>
}
export default TablePage;

于是我们便得到一个组件,将以上组件稍加修改,把需要的数据变成属性传递进来,我们便得到一个可复用的,可拖拽列宽的表格.

注意

使用时必须要给column设置width

问题

当表格列很多时,会出现卡顿,不跟鼠标

use-antd-resizable-header Github

在搜索列宽拖拽的解决方案时,在ant-design的github 上看到这个

table组件能否支持拖拽调整列宽(伸缩列)? · Issue #32594 · ant-design/ant-design (github.com)
在这里插入图片描述
在下方我又看到这个
在这里插入图片描述

于是…

安装
yarn add @minko-fe/use-antd-resizable-header
#或者
npm add @minko-fe/use-antd-resizable-header
使用
import useARH from '@minko-fe/use-antd-resizable-header';
import '@minko-fe/use-antd-resizable-header/dist/style.css';

function App() {
  const columns = [];

  const { components, resizableColumns, tableWidth, resetColumns } = useARH({
    columns: useMemo(() => columns, []),
    // 保存拖拽宽度至本地localStorage
    columnsState: {
      persistenceKey: 'localKey',
      persistenceType: 'localStorage',
    },
  });

  return (
    <>
      <Table columns={resizableColumns} 
			components={components} dataSource={data} 
			scroll={{ x: tableWidth }}></Table>
        <ProTable
            columns={resizableColumns}
            components={components}
            dataSource={data}
            scroll={{ x: tableWidth }}
            ></ProTable>
        <Button onClick={() => resetColumns()}>重置宽度</Button>
    </>
  );
}

使用比较简单,只需要简单替换数据,即可实现动态拖拽

注意

不能给所有的column设置width,最后一列不能设置,否则将不能拖拽

总结

相比较下, react-resizable在多列时会出现卡顿,use-antd-resizable-header因为没有实时调整,而是松开鼠标后调整,就不会显得非常卡顿,而且写的代码更少,所以我选择use-antd-resizable,但其实都还有比较多的扩展可以实现,不过我是搞后端的,所以就这样吧.

React中使用Ant Design(antd)创建表格并且允许用户拖动时,如果你想保持最后一个固定度不变,你可以通过一些技巧来实现这个功能。下面是一个简单的步骤: 1. **设置表头组件**: 使用`Table`组件的`columns`属性,并在配置数组的最后添加一个特殊的,它的`width`属性设置为你希望固定的值,例如`200`,并且设置`resizable`属性为`false`,表示此不可被调整。 ```jsx import { Table } from 'antd'; const columns = [ ...// 其他配置 { title: '固定标题', dataIndex: 'fixedColumnData', width: 200, resizable: false, // 阻止调整 }, ]; ``` 2. **处理变化**: 当用户拖拽其他时,监听`onColumnsChange`事件。在这个回调函数里,检查新数组,如果长度大于最初的数减一,说明用户改变了某个度。在这种情况下,你需要将最后一个(固定)的度恢复到原始值。 ```jsx function handleColumnsChange(columns) { if (columns.length > initialColumns.length - 1) { const fixedIndex = columns.length - 1; // 固定的位置 columns[fixedIndex].width = 200; // 恢复固定度 } } <Table columns={columns} onColumnsChange={handleColumnsChange} /> ``` 3. **保存初始**: 初始化时存储所有的初始度,以便在需要时恢复。 ```jsx const [initialColumns, setInitialColumns] = useState([]); useEffect(() => { setInitialColumns(columns); }, [columns]); // 当columns发生变化时更新初始 //... ```
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值