@fw-组件/数据-网格
一个高性能,可编辑的数据网格,用于内置虚拟化,排序,过滤,列管理,以及批量编辑. 建造在 塔克表格 财务报告和审定财务报表 TanStack 虚拟。 。 。 .
特征
- 🚀 虚拟渲染 ——用平滑滚动处理上千行
- ✏️ 单元格编辑 ——用文本、数字、日期、选择和布尔编辑器点击到编辑
- 📋 批量编辑 —— 选择多行并编辑全部字段
- 🔍 全球搜索 ——即时文本过滤与树意识匹配
- ↕️ 排序 ——单列和多列分拣
- 📌 列针 左边或右边的接线柱
- ↔️ 列调整大小 ——拖放以调整列大小
- 🌲 列扩展 ——带有自定义子内容的分级/记分数据
- ☑️ 行选择 ——带有全部选择的复选框
- 🎨 可自定义 ——自定义单元格渲染器,编辑组件和样式
- ♿ 可访问 ——适当ARIA角色,键盘导航
- 📦 零运行时间 – 只有React和TanStack作为同行依赖关系
安装
npm install @fw-components/data-grid @tanstack/react-table @tanstack/react-virtual
同伴依赖关系
{
"react": ">=18.0.0",
"react-dom": ">=18.0.0",
"@tanstack/react-table": "^8.0.0",
"@tanstack/react-virtual": "^3.0.0"
}
样式
包装一个预建的,即用即用样式表,在自己的应用中不需要Tailwind来使用. 这些组件释放出的所有工具类都与 fwgrid: 前缀( 如 ). fwgrid:flex, (中文(简体) ), fwgrid:bg-blue-600)),因此它们不能与你的应用程序自己的"Tailwind"(或其他)类相撞,并且只有被网格实际使用的类被纳入到构建中. 有两种方式可以将样式表带入您的应用程序.
选项1: CSS 文件导入( 常规 DOM)
对于普通(非阴影- root) 应用程序, 在您的应用程序入口处导入一次 CSS 文件, 并让您的捆绑者将其作为一个 <link>内置 <style> 通常方式:
import "@fw-components/data-grid/styles.css";
备选案文2:CSS-s-string导入(Shadow DOM/动态注射)
如果你的应用软件(或其中一部分制造电网的部分) 生活在阴影的根里 一个平地 <link>/全球 <style> 标记不会到达它。 对于这个案例(或者其他任何需要CSS作为JS字符串而非文件路径的情景,例如,你自己的构建管道无法按-是处理预编译的CSS文件),同样编译的输出也作为JS模块发布:
import { styles } from "@fw-components/data-grid/styles";
const sheet = new CSSStyleSheet();
sheet.replaceSync(styles);
shadowRoot.adoptedStyleSheets = [sheet];
或者,不支持可构造的样式表, 将它注入内线 <style> 标签 :
import { styles } from "@fw-components/data-grid/styles";
const styleTag = document.createElement("style");
styleTag.textContent = styles;
document.head.appendChild(styleTag);
快速启动
import { DataGrid } from "@fw-components/data-grid";
import type { ColumnDef } from "@fw-components/data-grid";
interface Asset {
id: string;
name: string;
sector: string;
value: number;
irr: number;
}
const columns: ColumnDef<Asset>[] = [
{ accessorKey: "name", header: "Asset Name" },
{ accessorKey: "sector", header: "Sector" },
{
accessorKey: "value",
header: "Value",
meta: { formatType: "currency", formatOptions: { currencyCode: "USD" }, align: "right" },
},
{
accessorKey: "irr",
header: "IRR",
meta: { formatType: "percentage", align: "right" },
},
];
function PortfolioDashboard() {
return (
<DataGrid
data={assets}
columns={columns}
getRowId={(row) => row.id}
features={{ virtualization: true, sorting: true }}
tableContainerClassName="h-[600px]"
/>
);
}
编辑
单元格编辑
允许通过 meta.editable 财务报告和审定财务报表 meta.editType数字 :
const columns: ColumnDef<Asset>[] = [
{
accessorKey: "name",
header: "Asset Name",
meta: { editable: true, editType: "text" },
},
{
accessorKey: "sector",
header: "Sector",
meta: {
editable: true,
editType: "select",
editOptions: [
{ value: "tech", label: "Technology" },
{ value: "health", label: "Healthcare" },
{ value: "finance", label: "Finance" },
],
},
},
{
accessorKey: "value",
header: "Value",
meta: { editable: true, editType: "number" },
},
{
accessorKey: "investmentDate",
header: "Date",
meta: { editable: true, editType: "date" },
},
{
accessorKey: "isActive",
header: "Active",
meta: { editable: true, editType: "boolean" },
},
];
<DataGrid
data={assets}
columns={columns}
getRowId={(row) => row.id}
features={{ editing: true }}
onCellEdit={async ({ rowId, columnId, value }) => {
await api.updateAsset(rowId, { [columnId]: value });
}}
validateCell={(value, row, columnId) => {
if (columnId === "name" && !value) return "Name is required";
return null;
}}
/>;
自定义编辑组件
用于复杂的编辑器(例如实体拾取器、合成选择),使用 meta.editCell数字 :
{
accessorKey: "assignee",
header: "Assignee",
meta: {
editable: true,
editType: "custom",
editCell: ({ value, onChange, onCommit, onCancel, error }) => (
<UserPicker
value={value}
onChange={onChange}
onSelect={(user) => { onChange(user); onCommit(); }}
onCancel={onCancel}
error={error}
/>
),
},
}
批量编辑
启用行选择,然后通过 onCellEdit 用于任何一行
当前选择将应用到所有所选行 :
function PortfolioDashboard() {
const [selectedIds, setSelectedIds] = useState<string[]>([]);
const handleCellEdit = async ({ rowId, columnId, value, row }: CellEditEvent<Asset>) => {
const isBulkTarget = selectedIds.length > 1 && selectedIds.includes(rowId);
const targetIds = isBulkTarget ? selectedIds : [rowId];
await Promise.all(targetIds.map((id) => api.updateAsset(id, { [columnId]: value })));
};
return (
<DataGrid
data={assets}
columns={columns}
getRowId={(row) => row.id}
features={{ rowSelection: true, editing: true }}
onCellEdit={handleCellEdit}
onStateChange={{ onRowSelectionChange: setSelectedIds }}
/>
);
}
行选择
<DataGrid
data={assets}
columns={columns}
getRowId={(row) => row.id}
features={{
rowSelection: {
enabled: true,
columnPosition: "start",
pinned: "left",
width: 40,
enableSelectAll: true,
},
}}
onStateChange={{
onRowSelectionChange: (selection) => console.log("Selected:", selection),
}}
/>
虚拟化
默认启用虚拟化 。 大型数据集的最佳性能:
<DataGrid
data={largeDataset} // 10,000+ rows
columns={columns}
getRowId={(row) => row.id}
features={{ virtualization: true }}
virtualizationConfig={{
estimatedRowHeight: 48, // Helps virtualizer estimate scroll size
overScan: 10, // Extra rows rendered outside viewport
}}
tableContainerClassName="h-[80vh]" // Container must have a fixed height!
/>
⚠️ 重要:表容器必须有一个固定的高度(通过类名或样式),以便虚拟化工作.
列格式化
财务数据内置格式化器:
const columns: ColumnDef<Asset>[] = [
{
accessorKey: "marketValue",
header: "Market Value",
meta: {
formatType: "currency",
formatOptions: { currencyCode: "USD", numberFormat: "Millions", decimals: 1 },
align: "right",
},
},
{
accessorKey: "irr",
header: "IRR",
meta: { formatType: "percentage", formatOptions: { decimals: 2 } },
},
{
accessorKey: "multiple",
header: "TVPI",
meta: { formatType: "ratio" },
},
{
accessorKey: "investmentDate",
header: "Investment Date",
meta: { formatType: "date", formatOptions: { dateFormat: "MMM DD, YYYY" } },
},
];
可用格式类型 : currency, (中文(简体) ), percentage, (中文(简体) ), decimal, (中文(简体) ), number, (中文(简体) ), text, (中文(简体) ), date, (中文(简体) ), ratio, (中文(简体) ), boolean
自定义格式函数
{
accessorKey: "logoUrl",
header: "Logo",
meta: {
formatFn: (value) => <img src={value} className="w-8 h-8 rounded" alt="" />,
},
}
API 参考
<DataGrid> 道具
| Prop | 类型 | 说明 |
|---|---|---|
data | TData[] | 要求. 行数据阵列 |
columns | ColumnDef<TData>[] | 要求. 栏定义 |
getRowId | (row, index) => string | 稳定行ID功能( 编辑/ 选择关键) |
features | DataGridFeatures | 启用/ 残疾特性 |
state | Partial<TableState> | 控制状态 |
onStateChange | TableStateHandlers | 状态更改回调 |
initialState | Partial<TableState> | 初始状态值 |
onCellEdit | (event) => void | 单元格编辑传输处理器 |
validateCell | (value, row, colId) => string | null | 单元格验证 |
onTableReady | (table) => void | TanStack 表格实例调用 |
onRowClick | (row) => void | 行点击处理器 |
isLoading | boolean | 显示装入状态 |
emptyState | object | 空状态配置 |
errorMessage | ReactNode | 错误的状态消息 |
className | string | 外包装类 |
tableContainerClassName | string | 滚动容器类别 |
getRowClassName | (row, depth) => string | 动态行样式 |
DataGridFeatures
interface DataGridFeatures {
globalFilter?: boolean | { manual?: boolean };
sorting?: boolean | { multi?: boolean; manual?: boolean };
expanding?: boolean;
columnResizing?: boolean;
columnPinning?: boolean;
virtualization?: boolean;
rowSelection?: boolean | RowSelectionConfig;
editing?: boolean | EditingConfig;
}
列 元
扩展列定义为 meta数字 :
{
editable?: boolean;
editType?: "text" | "number" | "date" | "select" | "boolean" | "custom";
editOptions?: { value: string; label: string }[];
editCell?: (props: EditCellRenderProps) => ReactNode;
validate?: (value, row) => string | null;
formatType?: "currency" | "percentage" | "decimal" | "number" | "text" | "date" | "ratio" | "boolean";
formatOptions?: FormatOptions;
formatFn?: (value, cell) => ReactNode;
align?: "left" | "center" | "right";
width?: string | number;
minWidth?: string | number;
maxWidth?: string | number;
headerClassName?: string;
cellClassName?: string;
}
钩子
useEditing(options)
管理单元格级别的编辑状态。 存储单元格外组件的草稿,用于虚拟化安全.
useDataGridState(options)
中央国家管理部门得到控制/不受控制的支持.
键盘快捷键
| 密钥 | 行动 |
|---|---|
Enter 编号 : F2 | 开始编辑单元格 |
Enter | 提交编辑 |
Escape | 取消编辑 |
Tab | 移动到下一个单元格( 当编辑时) |
Space | 切换复选框/ 扩展行 |
显示大小写/ demo
运行交互式演示以尝试所有特性 :
cd showcase/data-grid
npm install
npm run dev
Open http://localhost:5173 看投资组合仪表板演示 资产500+,, 可编辑列,虚拟化等.
浏览器支持
- 克罗梅/第90号+
- Firefox 90+ (英语)
- 15岁以上
捐款
见 捐款额 (c) 发展结构和准则.