文章介绍了如何在AntDesign3.x中利用react-resizable实现列的可伸缩功能,包括安装方法、组件封装和解决松开鼠标仍能拖动的问题。同时提到了使用`use-antd-resizable-header`库的改进方案,使得列伸缩更为便捷和稳定。 摘要由CSDN通过智能技术生成

需求背景:需要实现Antd Table 组件的列伸缩,宽度可以拖拽

在Antd 3.x 的版本中是保留的列伸缩的Demo例子的:
在这里插入图片描述
借助 react-resizable 可以实现伸缩列。

# npm 安装
npm install react-resizable --save
# yarn 安装
yarn add react-resizable

参考官方的Demo,封装一个ResizableTable组件:

import { Table } from 'antd';
import type { ColumnsType } from 'antd/lib/table';
import { useEffect,useState } from 'react';
import { Resizable } from 'react-resizable';
import styles from './resizableTable.less';
 * 处理松开鼠标还会拖动的问题
 * 参考思路:在点击拖动时,使用浏览器API Selection.removeAllRanges 清空原本误选的文本。
const clearSelection = () => {
  if (window.getSelection) {
    const selection = window.getSelection();
    if (selection) {
      if (selection.empty) {
        // Chrome
        selection.empty();
      } else if (selection.removeAllRanges) {
        // Firefox
        selection.removeAllRanges();
   else if (document.selection && document.selection.empty) {
     // IE
     document.selection.empty();
export const ResizableTitle = (props: any) => {
  const { onResize, width, minWidth, maxWidth, ...restProps } = props;
  // 没有原始宽度的列,不支持伸缩;会出现从自适应宽度一下子跳到拖动位置;也可以自行增加参数,如 disableResize
  if (!width) {
    return <th {...restProps} />;
  const minConstraints: [number, number] | undefined = minWidth
    ? [minWidth, -Infinity]
    : undefined;
  const maxConstraints: [number, number] | undefined = maxWidth
    ? [maxWidth, +Infinity]
    : undefined;
  return (
    <Resizable
      width={width}
      height={0} // 不需要调整高度,设为 0
      minConstraints={minConstraints}
      maxConstraints={maxConstraints}
      handle={
          className="react-resizable-handle"
          onClick={(e) => {
            // 阻止冒泡
            e.stopPropagation();
      onResize={onResize}
      draggableOpts={{
        enableUserSelectHack: false,
        onMouseDown: () => {
          // 处理在 Windows Chrome 和 Edge 松开鼠标依然能拖动
          clearSelection();
      <th {...restProps} />
    </Resizable>
interface DataType {
  name: {
    first: string;
    last: string;
  gender: string;
  email: string;
  login: {
    uuid: string;
const columnsData: ColumnsType<DataType> = [
    title: 'Name',
    dataIndex: 'name',
    sorter: true,
    render: (name) => `${name.first} ${name.last}`,
    width: '20%',
    title: 'Gender',
    dataIndex: 'gender',
    filters: [
      { text: 'Male', value: 'male' },
      { text: 'Female', value: 'female' },
    width: '20%',
    title: 'Email',
    dataIndex: 'email',
const ResizableTable = () => {
  const curColumns: ColumnsType<DataType> = columnsData; // 可以是通过props 传进来的,这里用常量做例子
  const [column, setColumns] = useState<ColumnsType<any>>([]);
  // 拖动时更新表格列
  const handleResize = (index: number) => {
    return (_e: any, { size }: any) => {
      const newCols = [...column];
      newCols[index] = {
        ...newCols[index],
        width: size.width || '100%',
      setColumns(newCols);
  const mergeColumns = column.map((col, index) => ({
    ...col,
    onHeaderCell: (column: any) => ({
      width: column.width ?? 100,
      // 每一列增加 minWidth, maxWidth 作为 ResizableTitle 的 props
      minWidth: 50,
      // maxWidth: 1000,
      onResize: handleResize(index),
    }),
  }));
  useEffect(() => {
    console.log('变化', curColumns);
    if (curColumns) {
      setColumns(curColumns);
  }, [curColumns]);
  return (
    <div className={styles.resizeTable}>
      <Table
        size="small"
        components={{
          header: {
            cell: ResizableTitle,
        columns={mergeColumns}
        dataSource={[]}
    </div>
export default ResizableTable;

必须引入样式 resizableTable.less

.resizeTable {
  :global {
    .react-resizable {
      position: relative;
      background-clip: padding-box;
    .react-resizable-handle {
      position: absolute;
      width: 10px;
      height: 100%;
      bottom: 0;
      right: -5px;
      cursor: col-resize;
      background-image: none;
      z-index: 1;
    .ant-table-filter-column,
    .ant-table-column-sorters {
      display: flex;
      /* co1umn 从上到下 */
      align-items: center;
      /* center代表水平方向 */
      justify-content: space-around;
      min-width: 70px;
    .ant-table-thead>tr>th .ant-table-column-sorter {
      // margin-top: -21px;
      display: table-cell;
      vertical-align: middle;

必须保持一列宽度不设置,自适应。否则效果不对。

但我用这个插件后还是不太 OK,总有一些bug,比如如果拖动了不设置宽的列,整个伸缩就会变形;而且如果列数很多的情况下,自适应列效果不理想。

所有这个方案能用但不是很好用。
可以参考:https://juejin.cn/post/7182423243553734717

后续解决方案:

在查阅资料时,看到有个大佬封装好了一个伸缩hook use-antd-resizable-header,使用起来方便简单。遂引入项目。
https://github.com/hemengke1997/use-antd-resizable-header

pnpm add @minko-fe/use-antd-resizable-header

在这里插入图片描述
引入封装组件示例:

import { Table } from 'antd';
import { useAntdResizableHeader } from '@minko-fe/use-antd-resizable-header';
import '@minko-fe/use-antd-resizable-header/dist/style.css';
/** 自定义函数 */
import { isLocaleEn } from '@/utils/commont_rely';
/** type 类申明 */
import type { IProps } from '..'; // 自己封装的表格propsType, 仅作参考
/** 自定义样式 */
import './style.less';
/** ===================================
 * @name: 可伸缩列的表格组件
 * 注意:至少一列不能拖动(width 不设置即可),请保持至少一列的宽自适应
 *======================================*/
interface ResizableTableProps extends IProps {
  // 特殊配置
  defaultWidth?: number; // 设置不能拖动列的最小宽度 默认 120
  minConstraints?: number; // 拖动最小宽度 默认 60
  maxConstraints?: number; // 拖动最大宽度 默认800 可设置无穷
export default function ResizableTable(props: ResizableTableProps) {
  const { title, defaultWidth, minConstraints, maxConstraints } = props;
  const columns = props?.columns || []; // 组件传过来的colums
  const { components, resizableColumns, tableWidth } = useAntdResizableHeader({
    columns,
    defaultWidth: defaultWidth || 120,
    minConstraints: minConstraints || 60,
    maxConstraints: maxConstraints || 800,
  });
  return (
    <div className="resizableTable">
      <Table
        title={title}
        size="small"
        dataSource={data} // 组件传过来的data
        columns={resizableColumns}
        components={components}
        scroll={{ x: tableWidth }}
    </div>

使用方便,效果理想,推荐使用这个插件。

11.29 更新
升级到v2.9.0 ,不需要引入css文件
注意: 依赖包的名字也变了
pnpm add use-antd-resizable-header

通过 集成 react-resizable 来实现伸缩。 首先引入Resizable import { Resizable } from ‘react-resizable’; 通过替换table组件本身的components中的header的cell; 将每一个th都用Resizable包裹起来 如下(如下) //仅代表思路的代码 <Resizable width={width} height={0} onResize={onResize}
问题描述: 为了向用户展示更丰富的数据,更多的内容,需在展示的表页中设置宽可随意拖动。antd官网提供了宽可拖动的示例,经测试原示例并不好用,且使用有限制,宽拖拽响应很慢,拖动时会造成其它宽比较大的变化,针对内容较多的并不能做到随着宽的变化,内容也相应增减。 antd现可伸缩问题展示 1. antd官网示例,当宽拖动到比内容小时,内容将会出现换行,将行高度撑开 2....
import { FC, useState } from 'react' import { Resizable } from 'react-resizable' // 引入react-resizable npm i xxx 或 yarn add xxx import { deBounce } from '@/utils/utilConvenrt' // 防抖
经过一番排查发现 antd3.x是有可伸缩这一项的demo的 地址是:https://ant.design/components/table-cn/#components-table-demo-resizable-column 当我用该地址切换4.x,4.x出现了可伸缩这一个demo 而当我去掉url的#components-table-demo-resizable-colum 实现方式 react-resizable GitHub 首先百度寻找解决方案,很容易的,我们就找到了react-resizable,这个解决方案在antd 3.x 的文档中,表格 Table - Ant Design,但是在更高的版本中没有,如果不是百度,我应该永远找不到. npm install --save react-resizable 官方提供的代码示例: import { Ta 遇到的问题是官方可伸缩拖动的时候太卡,究其原因是实时更新宽,拖动的时候直接更新所有宽,当较多的时候更新的数据响应也会比较多,但做法是官方的延申 package.json "dependencies": { "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.3.2", "@testing-library/user-event": "^7.1.2", "antd": "^ function exportToExcel(data, fileName) { const sheetName = 'Sheet1'; const workbook = XLSX.utils.book_new(); const worksheet = XLSX.utils.json_to_sheet(data); XLSX.utils.book_append_sheet(workbook, worksheet, sheetName); const excelBuffer = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' }); saveAs( new Blob([excelBuffer], { type: 'application/octet-stream' }), `${fileName}.xlsx`, 最后,在需要导出 Excel 表格的事件中调用这个函数即可: ```javascript handleExportExcel = () => { const data = [ { name: 'John Doe', age: 35 }, { name: 'Jane Doe', age: 30 }, exportToExcel(data, 'users'); 这个例子中,我们将一个包含两个用户信息的数组作为数据传入,将文件名设置为 `users`,点击按钮后就会弹出下载 Excel 文件的窗口。