基于React+Tailwind实现带固定表头的可滚动动态表格
实现固定表头+滚动表格主体(React + Tailwind)
完全可以实现你要的效果,原生<tbody>无法直接设置滚动是因为表格布局的特性限制,我们可以通过拆分表头和表体、添加滚动容器的方式解决,同时支持动态添加行。
核心实现思路
- 将表头与表体拆分为两个独立的
<table>,放入同一容器保证列宽对齐 - 给表体容器设置固定高度和
overflow-y: auto,仅在表体区域显示滚动条 - 通过统一列宽设置避免表头与表体错位
- 维护表格数据状态,实现动态添加行功能
修正后的完整代码
import { useState } from 'react'; const AreaRow = ({ area, dependsOn, collaborators, selected, onRowSelect }) => ( <tr className="border-b border-gray-200 hover:bg-gray-50"> <td className="p-2"> <input type="checkbox" checked={selected} onChange={onRowSelect} /> </td> <td className="p-2">{area}</td> <td className="p-2">{dependsOn}</td> <td className="p-2">{collaborators}</td> <td className="p-2"> <button className="text-blue-600 hover:text-blue-800">...</button> </td> </tr> ); const DynamicTable = () => { // 初始表格数据 const [areas, setAreas] = useState([ { area: "市场部", dependsOn: "总经理", collaborators: 5 }, { area: "技术部", dependsOn: "CTO", collaborators: 12 }, { area: "人事部", dependsOn: "总经理", collaborators: 3 }, ]); const [selectedRows, setSelectedRows] = useState(Array(areas.length).fill(false)); // 全选逻辑 const handleHeaderCheckboxChange = (e) => { setSelectedRows(Array(areas.length).fill(e.target.checked)); }; // 单行选择逻辑 const toggleRowSelection = (index) => { setSelectedRows(prev => { const newArr = [...prev]; newArr[index] = !newArr[index]; return newArr; }); }; // 动态添加新行 const addNewRow = () => { setAreas(prev => [...prev, { area: "", dependsOn: "", collaborators: 0 }]); setSelectedRows(prev => [...prev, false]); }; return ( <div className="w-full overflow-hidden"> {/* 固定表头 */} <table className="border-collapse w-full"> <thead className="[&>tr>th]:text-left [&>tr>th]:p-2 [&>tr>th]:text-[#251AC7] [&>tr>th]:font-medium"> <tr className="bg-[#f5f6f8]"> <th style={{ width: '10%' }}> <input type="checkbox" onChange={handleHeaderCheckboxChange} /> </th> <th style={{ width: '30%' }}>Áreas</th> <th style={{ width: '20%' }}>Depende de</th> <th style={{ width: '10%' }}>Colaboradores</th> <th style={{ width: '5%' }}></th> </tr> </thead> </table> {/* 可滚动的表体容器 */} <div className="h-[330px] overflow-y-auto"> <table className="border-collapse w-full"> <tbody className="[&>tr>td]:text-left"> {areas.map((area, i) => ( <AreaRow key={i} area={area.area} dependsOn={area.dependsOn} collaborators={area.collaborators} selected={selectedRows[i]} onRowSelect={() => toggleRowSelection(i)} /> ))} </tbody> </table> </div> {/* 添加行按钮 */} <button onClick={addNewRow} className="mt-3 px-4 py-2 bg-[#251AC7] text-white rounded hover:bg-opacity-90" > 添加新行 </button> </div> ); }; export default DynamicTable;
关键修改说明
- 拆分表头表体:将原单个
<table>拆分为两个,表头独立存在,表体放入带滚动属性的<div>中,实现表头固定 - 滚动容器配置:给表体外层
<div>设置h-[330px] overflow-y-auto,仅表体区域显示垂直滚动条 - 列宽对齐:保持表头与表体的列宽设置完全一致,避免布局错位
- 动态行逻辑:新增
addNewRow函数,通过更新状态数组实现添加空行,同步维护选中状态数组 - 样式优化:添加行边框和hover效果提升可读性,移除原tbody上无效的边框设置
额外注意事项
- 若需更精准的列宽控制,可替换百分比为固定像素值(如
w-[100px]),确保列宽完全匹配 - 若需横向滚动,可给最外层容器添加
overflow-x-auto,如需表头同步横向滚动,可给表头列添加sticky left-0定位 - 尽量避免用索引作为
key,如果数据有唯一ID,优先使用唯一ID以提升渲染性能
内容的提问来源于stack exchange,提问作者La Bola Al Riel
相关产品推荐
相关产品推荐

