如何在Ant-Design Table组件实现自定义排序?

Ant-Design中使用Table组件实现多列排序,怎么实现自定义排序(默认排序顺序是升序->降序->取消排序)。以及只能通过点击上下箭头进行排序,而不是点击列头进行排序。实现效果类似Element-UITable组件的列排序的交互。

通过提供对应的API,没能实现这样的功能。

阅读 436
2 个回答
import React, { useState } from 'react';
import { Table } from 'antd';
import { CaretUpOutlined, CaretDownOutlined } from '@ant-design/icons';

const CustomTable = () => {
  const [sortState, setSortState] = useState({
    column: null,
    order: null // null: 未排序, 'ascend': 升序, 'descend': 降序
  });

  // 自定义排序图标
  const CustomSorter = ({ column }) => {
    const isActive = sortState.column === column;
    return (
      <span className="custom-sorter">
        <CaretUpOutlined 
          className={`sort-caret ascending ${isActive && sortState.order === 'ascend' ? 'active' : ''}`}
          onClick={(e) => {
            e.stopPropagation();
            handleSort(column, 'ascend');
          }}
        />
        <CaretDownOutlined 
          className={`sort-caret descending ${isActive && sortState.order === 'descend' ? 'active' : ''}`}
          onClick={(e) => {
            e.stopPropagation();
            handleSort(column, 'descend');
          }}
        />
      </span>
    );
  };

  const handleSort = (column, order) => {
    if (sortState.column === column && sortState.order === order) {
      setSortState({
        column: null,
        order: null
      });
    } else {
      setSortState({
        column,
        order
      });
    }
  };

  const columns = [
    {
      title: '姓名',
      dataIndex: 'name',
      key: 'name',
      sortDirections: ['ascend', 'descend'],
      showSorterTooltip: false,
      sorter: true,
      title: (
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
          <span>姓名</span>
          <CustomSorter column="name" />
        </div>
      ),
    },
    {
      title: '年龄',
      dataIndex: 'age',
      key: 'age',
      sortDirections: ['ascend', 'descend'],
      showSorterTooltip: false,
      sorter: true,
      title: (
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
          <span>年龄</span>
          <CustomSorter column="age" />
        </div>
      ),
    },
    // ... 
  ];

  const data = [
    { key: '1', name: '张三', age: 25 },
    { key: '2', name: '李四', age: 30 },
    { key: '3', name: '王五', age: 28 },
  ];

  const handleTableChange = (pagination, filters, sorter) => {
    if (!sortState.column || !sortState.order) {
      return data;
    }

    return [...data].sort((a, b) => {
      const column = sortState.column;
      if (sortState.order === 'ascend') {
        return a[column] > b[column] ? 1 : -1;
      }
      return a[column] < b[column] ? 1 : -1;
    });
  };

  return (
    <>
      <style jsx>{`
        .custom-sorter {
          display: inline-flex;
          flex-direction: column;
          margin-left: 8px;
          cursor: pointer;
        }
        .sort-caret {
          color: #c0c4cc;
          transition: color 0.3s;
          font-size: 12px;
        }
        .sort-caret.active {
          color: #1890ff;
        }
        .sort-caret:hover {
          color: #1890ff;
        }
      `}</style>
      <Table 
        columns={columns}
        dataSource={handleTableChange()}
        pagination={false}
        onChange={handleTableChange}
      />
    </>
  );
};

export default CustomTable;
import React, { useState } from 'react';
import { Table } from 'antd';
import { CaretUpOutlined, CaretDownOutlined } from '@ant-design/icons';

const CustomSortTable = () => {
  const [dataSource, setDataSource] = useState([
    { id: 1, name: 'John', age: 32, score: 85 },
    { id: 2, name: 'Jim', age: 28, score: 92 },
    { id: 3, name: 'Tom', age: 35, score: 78 },
  ]);

  const [sortConfig, setSortConfig] = useState({
    columnKey: null,
    order: null
  });

  const handleSort = (columnKey) => {
    setSortConfig(prevConfig => {
      // 根据当前排序状态决定下一个排序状态
      if (prevConfig.columnKey !== columnKey) {
        // 如果是新的列,首先升序排序
        return { columnKey, order: 'ascend' };
      } else if (prevConfig.order === 'ascend') {
        // 如果已经是升序,则变为降序
        return { columnKey, order: 'descend' };
      } else if (prevConfig.order === 'descend') {
        // 如果已经是降序,则取消排序
        return { columnKey: null, order: null };
      }
      
      // 默认返回初始状态
      return { columnKey: null, order: null };
    });
  };

  const sortedData = React.useMemo(() => {
    if (!sortConfig.columnKey) return dataSource;

    return [...dataSource].sort((a, b) => {
      if (sortConfig.order === 'ascend') {
        return a[sortConfig.columnKey] > b[sortConfig.columnKey] ? 1 : -1;
      }
      if (sortConfig.order === 'descend') {
        return a[sortConfig.columnKey] < b[sortConfig.columnKey] ? 1 : -1;
      }
      return 0;
    });
  }, [dataSource, sortConfig]);

  const columns = [
    {
      title: 'Name',
      dataIndex: 'name',
      key: 'name',
      render: (text, record) => (
        <div className="flex items-center">
          {text}
          <div className="ml-2 flex flex-col cursor-pointer">
            <CaretUpOutlined 
              onClick={() => handleSort('name')}
              style={{ color: sortConfig.columnKey === 'name' && sortConfig.order === 'ascend' ? 'blue' : 'gray' }}
            />
            <CaretDownOutlined 
              onClick={() => handleSort('name')}
              style={{ color: sortConfig.columnKey === 'name' && sortConfig.order === 'descend' ? 'blue' : 'gray' }}
            />
          </div>
        </div>
      )
    },
    {
      title: 'Age',
      dataIndex: 'age',
      key: 'age',
      render: (text, record) => (
        <div className="flex items-center">
          {text}
          <div className="ml-2 flex flex-col cursor-pointer">
            <CaretUpOutlined 
              onClick={() => handleSort('age')}
              style={{ color: sortConfig.columnKey === 'age' && sortConfig.order === 'ascend' ? 'blue' : 'gray' }}
            />
            <CaretDownOutlined 
              onClick={() => handleSort('age')}
              style={{ color: sortConfig.columnKey === 'age' && sortConfig.order === 'descend' ? 'blue' : 'gray' }}
            />
          </div>
        </div>
      )
    },
    {
      title: 'Score',
      dataIndex: 'score',
      key: 'score',
      render: (text, record) => (
        <div className="flex items-center">
          {text}
          <div className="ml-2 flex flex-col cursor-pointer">
            <CaretUpOutlined 
              onClick={() => handleSort('score')}
              style={{ color: sortConfig.columnKey === 'score' && sortConfig.order === 'ascend' ? 'blue' : 'gray' }}
            />
            <CaretDownOutlined 
              onClick={() => handleSort('score')}
              style={{ color: sortConfig.columnKey === 'score' && sortConfig.order === 'descend' ? 'blue' : 'gray' }}
            />
          </div>
        </div>
      )
    }
  ];

  return (
    <Table 
      dataSource={sortedData} 
      columns={columns} 
      rowKey="id"
      pagination={false}
    />
  );
};

export default CustomSortTable;
推荐问题
宣传栏