You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React实现点击表格表头(th)对tbody数据进行排序

实现点击表头排序的方案

我来给你一步步拆解怎么实现这个点击表头排序的功能,完全结合你现有的代码结构来改,非常直观:

核心思路

用React状态追踪当前的排序字段和排序方向(升序/降序),点击表头时更新这两个状态,之后根据状态对数据数组进行排序,最后把排序后的数组渲染到tbody里。

具体实现步骤

1. 初始化排序状态

在你的组件内部添加两个状态,用来记录当前的排序规则:

import { useState, useMemo } from 'react';

// 组件内部
const [sortKey, setSortKey] = useState('number'); // 默认按number字段排序
const [sortDirection, setSortDirection] = useState('asc'); // 默认升序

2. 给表头添加点击事件&排序标识

修改你现有的表头渲染逻辑,给每个th加上点击事件,同时可以添加一个小箭头来提示当前的排序方向:

<thead>
  <tr>
    {headTitles.map(title => (
      <th 
        key={title} 
        onClick={() => handleSort(title)}
        style={{ cursor: 'pointer' }} // 鼠标变指针,提示可点击
      >
        <Translate use={`connekt_champions_table_${title}_title`} />
        {/* 可选:添加排序箭头,让用户直观看到当前排序状态 */}
        {sortKey === title && (
          <span style={{ marginLeft: '4px' }}>
            {sortDirection === 'asc' ? '↑' : '↓'}
          </span>
        )}
      </th>
    ))}
  </tr>
</thead>

然后实现handleSort函数,用来切换排序规则:

const handleSort = (title) => {
  // 如果点击的是当前正在排序的字段,就切换升/降序;否则默认设为升序
  if (sortKey === title) {
    setSortDirection(prev => prev === 'asc' ? 'desc' : 'asc');
  } else {
    setSortKey(title);
    setSortDirection('asc');
  }
};

3. 对数据进行排序(用useMemo优化性能)

用useMemo缓存排序后的数组,避免每次组件渲染都重复排序,提升性能:

const sortedData = useMemo(() => {
  // 先复制原数据,避免直接修改原数组
  const dataCopy = [...data];
  
  dataCopy.sort((a, b) => {
    const valueA = a[sortKey];
    const valueB = b[sortKey];

    // 处理数字类型字段(比如number、mastery_level、points等)
    if (typeof valueA === 'number' && typeof valueB === 'number') {
      return sortDirection === 'asc' ? valueA - valueB : valueB - valueA;
    }

    // 处理字符串/日期类型字段(比如champion、last_played)
    if (typeof valueA === 'string' && typeof valueB === 'string') {
      // 先判断是不是日期格式,是的话转成Date对象排序
      const dateA = new Date(valueA);
      const dateB = new Date(valueB);
      if (!isNaN(dateA.getTime()) && !isNaN(dateB.getTime())) {
        return sortDirection === 'asc' ? dateA - dateB : dateB - dateA;
      }
      // 普通字符串按字典序排序
      return sortDirection === 'asc' 
        ? valueA.localeCompare(valueB) 
        : valueB.localeCompare(valueA);
    }

    // 布尔类型字段(比如chest)可以单独处理,比如把true排前面
    if (typeof valueA === 'boolean' && typeof valueB === 'boolean') {
      return sortDirection === 'asc' ? (valueA ? -1 : 1) : (valueA ? 1 : -1);
    }

    // 其他类型默认按升序
    return 0;
  });

  return dataCopy;
}, [data, sortKey, sortDirection]);

4. 渲染排序后的数据

把原来tbody里的data.map替换成sortedData.map就行:

<tbody>
  {sortedData.map((item, i) => (
    <tr key={item.number}> {/* 这里用item.number当唯一key,你可以换成实际的唯一标识字段 */}
      {/* 对应每个表头的单元格内容,比如: */}
      <td>{item.number}</td>
      <td>{item.champion}</td>
      <td>{item.mastery_level}</td>
      {/* 剩下的字段依次渲染... */}
    </tr>
  ))}
</tbody>

额外优化小技巧

  • 给表头加个hover样式,提升用户体验:
th:hover {
  background-color: #f0f0f0;
  transition: background-color 0.2s;
}
  • 如果有特殊格式的字段(比如progress的百分比),可以先提取数字再排序,比如parseFloat(valueA)。

内容的提问来源于stack exchange,提问作者Krešimir Galić

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 03:54:39