About fineui-grid
fineui-grid is a development skill for building FineUI data grids, intended for developers displaying, selecting, editing, and processing tabular data. It covers F.js, Pro, Core modes, and Java, explaining how configuration and data handling differ across stacks.
Key features
- 01Configure columns and custom rendering
- 02Load local or server-side data
- 03Select rows and read selected data
- 04Support paging, sorting, and filtering
- 05Edit cells and group data
Use cases
- 01Display business data with formatted columns
- 02Implement server-side paging and sorting
- 03Add row selection, filtering, or editing interactions
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ sanshi/ fineui-skills --skill fineui-gridAfter installing, type/fineui-gridin Claude Code to confirm it loaded.
Bundled files
References and scripts installed along with SKILL.md.
references/advanced.mdcolumns.mddata-loading.mdediting.mdfilter.mdheader.mdpaging-toolbar.mdrow-features.mdrow-group.mdselection.mdsorting.mdsummary.mdtree-grid.mdDetails
From the project READMEFineUI Grid(表格)技能
术语:4 部署栈(Core 含 3 种开发模式)
同一个 Grid,不同部署栈/模式写法不同。先确定目标,再动手,不要混用。
| 部署栈 | 开发模式 | 前台 UI 写法 | 后台/数据模型 |
|---|---|---|---|
| F.js | —(纯 JavaScript) | JS 配置对象 F.create({...}) | 纯前端 |
| Pro | WebForms | ASPX 服务器控件 <f:Grid runat="server"> | Page_Load/IsPostBack + designer |
| Core | MVC(经典 MVC) | Fluent API Html.F().Grid()... | Controller + ViewBag |
| Core | RazorForms(Core 推荐) | TagHelper <f:Grid>(PascalCase) | 三件套 + Page_Load/IsPostBack |
| Core | RazorPages | TagHelper <f:Grid>(PascalCase) | 两件套(无 designer)+ OnGet/OnPost |
| Java | Spring Boot | Thymeleaf 方言 <f:grid>(kebab-case) | 两件套(.html + 页面类 .java,无 designer)+ Page_Load/isPostBack() |
RazorForms 与 RazorPages 共用 TagHelper 标签语法(
<f:Grid>/<f:RenderField>等标签名、列属性相同),但不是完全相同——数据初始化与事件挂接的推荐写法不同:
- RazorForms:数据在后台
Page_Load里Grid1.DataSource=...; Grid1.DataBind();(<f:Grid>标签上不写DataSource);按钮OnClick="方法名"。- RazorPages:数据在标签上内联
DataSource="@Model.GetXxx()";按钮OnClick="@Url.Handler(\"方法名\")"。FineUI.Java 是 Core-RazorForms 的「孪生栈」:同样「标签式有状态服务端组件 +
Page_Load/isPostBack()+ 控件字段 +xxx_Click/事件处理器」,差异只在后台栈——标签/属性全 kebab-case(<f:grid>/<f:render-field data-field=…>),页面类用 Java Bean setter/getter(Grid1.setDataSource(...); Grid1.dataBind();),处理器返回void(纯 JSON 增量回发,无需UIHelper.Result())。客户端 F.js 运行时四栈完全相同——F.ui.Grid1.xxx()、渲染函数、notifySelectedRows('Grid1')、监听器 JS 一字不改。详见fineui-foundation。
何时使用(When to Use)
- 展示表格数据,配置列(文本/数字/日期/格式化/自定义渲染)
- 行选择:复选框多选、单选、读取选中行
- 数据加载:本地内联数据 / 服务端数据 / 服务端分页
- 单元格编辑、排序、筛选、分组、合计行、工具栏
开始前(Before You Start)—— 先判定"哪个模式"
判定线索:
.aspx→ Pro(WebForms);Controllers/+Views/*/Index.cshtml且用Html.F()(Fluent API)→ Core-MVC;Pages/*.cshtml用<f:Grid>标签 → Core-RazorForms(有.designer.cs)或 Core-RazorPages(无.designer.cs);纯前端.html→ F.js;.html里<html xmlns:f="http://fineui.com/java">+<f:grid>小写标签、pom.xml/mvnw、页面类.java带@FineUIPage(...)+extends FineUIPageBase→ Java(Spring Boot)。
再确认:数据从哪来?(本地内联 / 服务端)要不要编辑?要不要选择?
各写法速览(同一个基础表格)
// ① F.js
F.create({
type: 'Grid', isFluid: true, id: 'Grid1', renderTo: '#wrap', title: '表格',
idField: 'Id', textField: 'Name',
columns: [
{ columnType: 'rownumberfield' },
{ text: '姓名', field: 'Name' },
{ text: '入学年份', field: 'EntranceYear', fieldType: 'int' },
{ text: '所学专业', field: 'Major', flex: 1, minWidth: 150 }
],
data: [{ Id: 1, Name: '张三', EntranceYear: 2020, Major: '软件工程' }]
});
<%-- ② Pro(WebForms,.aspx)--%>
<f:Grid ID="Grid1" runat="server" IsFluid="true" ShowBorder="true" ShowHeader="true" Title="表格" DataIDField="Id" DataKeyNames="Id">
<Columns>
<f:RowNumberField />
<f:RenderField ColumnID="Name" DataField="Name" HeaderText="姓名" />
<f:RenderField ColumnID="EntranceYear" DataField="EntranceYear" FieldType="Int" HeaderText="入学年份" />
<f:RenderField ColumnID="Major" DataField="Major" ExpandUnusedSpace="true" MinWidth="150px" HeaderText="所学专业" />
</Columns>
</f:Grid>
// ②后台 Grid.aspx.cs
protected void Page_Load(object sender, EventArgs e) {
if (!IsPostBack) { Grid1.DataSource = GetDataTable(); Grid1.DataBind(); }
}
// ③ Core-MVC(Fluent API,Index.cshtml)
@{ var F = Html.F(); }
@(F.Grid().IsFluid(true).Title("表格").ID("Grid1").DataIDField("Id").DataTextField("Name")
.Columns(
F.RowNumberField(),
F.RenderField().HeaderText("姓名").DataField("Name"),
F.RenderField().HeaderText("入学年份").DataField("EntranceYear").FieldType(FieldType.Int),
F.RenderField().HeaderText("所学专业").DataField("Major").ExpandUnusedSpace(true).MinWidth(150)
)
.DataSource(ViewBag.Grid1DataSource) // Controller: ViewBag.Grid1DataSource = GetDataTable();
)
<!-- ④ Core-RazorForms(TagHelper):标签不写 DataSource,数据在后台 Page_Load 绑定 -->
<f:Grid ID="Grid1" IsFluid="true" ShowBorder="true" ShowHeader="true" Title="表格" DataIDField="Id" DataTextField="Name">
<Columns>
<f:RowNumberField />
<f:RenderField HeaderText="姓名" DataField="Name" />
<f:RenderField HeaderText="入学年份" DataField="EntranceYear" FieldType="Int" />
<f:RenderField HeaderText="所学专业" DataField="Major" ExpandUnusedSpace="true" MinWidth="150" />
</Columns>
</f:Grid>
// ④后台 Grid.cshtml.cs(partial,配 designer.cs)
protected void Page_Load(object sender, EventArgs e) {
if (!IsPostBack) { Grid1.DataSource = GetDataTable(); Grid1.DataBind(); }
}
<!-- ⑤ Core-RazorPages(TagHelper):列同④,但数据在标签上内联绑定 -->
<f:Grid ID="Grid1" IsFluid="true" ShowBorder="true" ShowHeader="true" Title="表格"
DataIDField="Id" DataTextField="Name" DataSource="@Model.GetDataTable()">
<Columns>
<%-- 列标签与④完全一致 --%>
</Columns>
</f:Grid>
<!-- ⑥ FineUI.Java(Thymeleaf 方言):标签/属性全 kebab-case;列同④结构,数据在页面类 Page_Load 绑定 -->
<!DOCTYPE html>
<html xmlns:f="http://fineui.com/java" layout:decorate="~{shared/layout}">
<head><title>FineUI.Java · 基础表格</title></head>
<body>
<th:block layout:fragment="body">
<f:grid id="Grid1" is-fluid="true" show-border="true" show-header="true" title="表格" data-id-field="Id" data-text-field="Name">
<f:columns>
<f:row-number-field></f:row-number-field>
<f:render-field header-text="姓名" data-field="Name"></f:render-field>
<f:render-field header-text="入学年份" data-field="EntranceYear" field-type="Int"></f:render-field>
<f:render-field header-text="所学专业" data-field="Major" expand-unused-space="true" min-width="150"></f:render-field>
</f:columns>
</f:grid>
</th:block>
<th:block layout:fragment="script"><script src="/res/js/grid.js"></script></th:block>
</body>
</html>
// ⑥后台 Grid.java(页面类,无 designer;字段名 = 标签 id)
@FineUIPage("grid/grid")
public class Grid extends FineUIPageBase {
com.fineui.java.core.controls.Grid Grid1; // 全限定名避免与本页类名 Grid 冲突;或 import 后写 Grid Grid1;
public void Page_Load(Object sender, EventArgs e) {
if (!isPostBack()) { Grid1.setDataSource(getDataList()); Grid1.dataBind(); }
}
}
参考文档(Documentation Reference Files)
表格是最复杂组件,按功能分类拆成 13 个参考文件。按需求只读相关的那几篇,不必全读。
基础(数据 / 列 / 分页 / 选择 / 编辑)
| 文件 | 何时读 |
|---|---|
| references/columns.md | 列定义、列类型、格式化(日期/数字)、自定义渲染、固定列 |
| references/data-loading.md | 内存分页 / 数据库分页、翻页事件回发、RecordCount |
| references/editing.md | 单元格编辑、列编辑器、读取编辑数据(各栈 API 差异) |
| references/selection.md | 行选择:复选框多选/单选、默认选中、读取与设置选中行 |
| references/paging-toolbar.md | 分页工具栏、页大小选择器、窄屏简洁分页、全局配置 |
数据处理(排序 / 合计 / 过滤 / 分组 / 树)
| 文件 | 何时读 |
|---|---|
| references/sorting.md | 客户端/服务端排序、多列排序、按别的字段排、自定义排序函数 |
| references/summary.md | 合计行:客户端/服务端、当前页/全部、浮动、多行 |
| references/filter.md | 表头过滤:文本/数字/日期/下拉/复选、多条件、行内过滤、服务端过滤处理 |
| references/row-group.md | 行分组:分组头渲染、展开折叠、组内小计 |
| references/tree-grid.md | 树表格:父子层级行、复选框级联、图标、分页 |
布局与交互(表头 / 行功能 / 高级)
| 文件 | 何时读 |
|---|---|
| references/header.md | 表头选项(隐藏/菜单/提示/列自定义属性)、多表头、动态创建列 |
| references/row-features.md | 行扩展列、弹窗列、行命令按钮、行单击/双击/选中事件、行/单元格样式、行高行密度 |
| references/advanced.md | 列锁定、列/行拖拽排序、单元格合并、大数据表格 |
概念 → 各写法属性名对照(Key Options at a Glance)
Core-RazorForms 与 Core-RazorPages 共用同一套 TagHelper 属性(下表 "Core-TagHelper" 列),差异在数据初始化/事件(见约束 5、6 与 selection.md)。Java 列单列,属性名 = Core-TagHelper 名转 kebab-case(属性「值」如
Int/Date仍保持 PascalCase)。
| 概念 | F.js | Pro (WebForms) | Core-MVC (Fluent API) | Core-TagHelper | Java (Thymeleaf 方言) |
|---|---|---|---|---|---|
| 组件 | type: 'Grid' | <f:Grid runat="server"> | F.Grid() | <f:Grid> | <f:grid> |
| 自适应宽度 | isFluid: true | IsFluid="true" | .IsFluid(true) | IsFluid="true" | is-fluid="true" |
| 行 ID 字段 | idField | DataIDField | .DataIDField() | DataIDField | data-id-field |
| 列集合 | columns: [ ] | <Columns> | .Columns( ) | <Columns> | <f:columns> |
| 行号列 | columnType:'rownumberfield' | <f:RowNumberField> | F.RowNumberField() | <f:RowNumberField> | <f:row-number-field> |
| 数据字段 | field | DataField | .DataField() | DataField | data-field |
| 列标题 | text | HeaderText | .HeaderText() | HeaderText | header-text |
| 字段类型 | fieldType | FieldType | .FieldType(FieldType.X) | FieldType | field-type="Int" |
| 内置渲染器 | (fieldType+fieldFormat) | Renderer+RendererArgument | .Renderer(Renderer.X).RendererArgument() | Renderer+RendererArgument | renderer="Date"+renderer-argument |
| 自定义 JS 渲染 | renderer: fn | RendererFunction="fn" | .RendererFunction("fn") | RendererFunction="fn" | renderer-function="fn" |
| 复选框多选 | checkboxSelect: true | EnableCheckBoxSelect="true" | .EnableCheckBoxSelect(true) | EnableCheckBoxSelect="true" | enable-check-box-select="true" |
相关技能(Related Skills)
fineui-foundation:F.create/ PageManager / 部署栈与模式总览 / RawHtml 安全模型 / 命名约定fineui-form:Grid 单元格编辑器、过滤字段用到的表单字段(TextBox / NumberBox / DropDownList 等)fineui-window:Grid 弹窗列用到的 Window 组件fineui-tree:独立的 Tree 控件(与 Grid 的"树表格"不同,见 tree-grid.md)
约束与规则(Constraints & Rules)
- 绝不编造 API:不确定的属性去查官网 API(见下方 Official Resources)或
F/doc/的 JSDoc,别猜。不同模式属性名不同,尤其别把某模式的名字用到另一模式。 - 先定模式、不混用:一个页面只用一种模式的写法。判定见「开始前」。F.js 用
text/field,C# 三模式用HeaderText/DataField,Java 用header-text/data-field(全 kebab-case)——不要串;Fluent API(MVC)与 TagHelper(RazorForms/RazorPages)不要混写。 - 文本默认 HTML 编码(RawHtml 安全模型):Grid 单元格/列头文本默认转义。要输出可信 HTML:
- F.js:列
renderer返回的字符串会作为 HTML 插入(渲染函数内自行保证可信);普通文本属性用F.rawHtml(...)。 - C#:给控件文本赋 HTML 用
xxx.TextRawHtml = new RawHtml("...");消息用ShowNotify(new RawHtml("..."))。绝不手写Text+TextRaw两个属性。 - Java:标签使用
xxx-raw-html(如header-text-raw-html/text-raw-html),服务端使用new RawHtml(...)与对应 setter;消息实例用notify.setMessageRawHtml(new RawHtml(...))后调用notify.show()。不要以encode-text="false"作为新代码的通用逃生口。渲染函数返回值与 F.js 一致(客户端插入)。
- F.js:列
- Pro 数据绑定固定套路:
!IsPostBack内Grid1.DataSource = table; Grid1.DataBind();。忘了!IsPostBack会在每次回发重复绑定、丢失状态。 - Core 三种模式的数据初始化各不相同:
- MVC(Fluent API):Controller 设
ViewBag.Grid1DataSource,View 里.DataSource(ViewBag.Grid1DataSource)。 - RazorForms:后台
Page_Load(!IsPostBack)里Grid1.DataSource=...; Grid1.DataBind();,<f:Grid>标签不写DataSource。 - RazorPages:标签上内联
DataSource="@Model.GetXxx()"。 - Java(同 RazorForms 范式):页面类
Page_Load(!isPostBack())里Grid1.setDataSource(list); Grid1.dataBind();,<f:grid>标签不写data-source;控件字段手动在类里声明(com.fineui.java.core.controls.Grid Grid1;,字段名 = 标签id);事件/命令处理器返回void(如public void Grid1_PageIndexChanged(Object sender, GridPageEventArgs e))。
- MVC(Fluent API):Controller 设
- RazorForms vs RazorPages(同为 TagHelper,但后台模型不同):RazorForms 三件套(
.cshtml+.cshtml.cspartial +.designer.cs),后台继承项目现有的 RazorForms 页面基类(官方示例为BaseModel,它本身可继承PageModel),使用Page_Load/IsPostBack、OnClick="方法名";同步控件事件返回void,按钮点击示例为protected void 方法名(object sender, EventArgs e),分页、排序、行命令等则使用各自的专用EventArgs,不写OnPost、不返回IActionResult、不调用UIHelper.Result()。RazorPages 两件套(非 partial、无 designer)、OnGet/OnPostXxx、OnClick="@Url.Handler(\"方法名\")",OnPostXxx返回IActionResult和UIHelper.Result();Java 两件套(.html+.java,无 designer)、Page_Load/isPostBack()、on-click="方法名"、@FineUIPage("area/page")定路由。 - 新代码只使用三栈共有列:普通列用
RenderField,布尔展示列用RenderCheckField,另有RowNumberField、GroupField及RenderField.Commands。不要根据 FineUI.Pro 的历史示例生成仅 Pro 存在的服务端渲染列。 - 行选择统一使用稳定行 ID:初始化、读取与服务端主动选中都先设置
DataIDField/data-id-field,再使用SelectedRowID/SelectedRowIDArray/getSelectedRowIdArray()。Pro/Core 的SelectedRowIndex/SelectedRowIndexArray已废弃,只用于识别和迁移旧代码;Java 已直接删除同名 getter/setter 与模板属性。读取选中行数据时,Pro / Core-RazorForms 调Grid1.GetSelectedDataKeys(),Java 调Grid1.getSelectedDataKeys();必须让DataKeyNames/_DataKeyNames/data-key-names包含行 ID 字段。数据库分页跨页选择或敏感业务只取稳定行 ID,再查询数据库。详见 references/selection.md。 - 三个"分组/层级"概念别混:多表头(列的分组,
GroupField,header.md)≠ 行分组(数据行按字段分组,EnableRowGroup,row-group.md)≠ 树表格(行父子层级,EnableTree,tree-grid.md)。用户说"分组"时先确认是哪一种。 - F.js 嵌套配置 vs .NET 拍平属性:多个高级功能 F.js 把选项收进一个对象(
tree:{...}/rowGroup:{...}/rowExpander:{...}/filter:{...}),而 Pro/Core 拍平成一堆独立属性(EnableTree/TreeColumn/...)。转写时注意这种结构差异。 - 行事件 EventArgs 类名按栈不同:同一行事件,Pro 与 RazorForms 的参数类名不一样(如行命令 Pro
GridCommandEventArgs/ RazorFormsGridRowCommandEventArgs)。Java 的类名与 Core 又不完全一致:行命令用GridCommandEventArgs(同 Pro),行单击/双击用GridRowEventArgs,行数据绑定用GridRowDataBoundEventArgs,翻页GridPageEventArgs、排序GridSortEventArgs(getter 取值,如e.getRowIndex()/e.getCommandName())。详见 row-features.md,别照抄错。 - 合并/拖拽无服务端属性:单元格合并(
mergeCells/mergeColumns)、行拖拽(moveRowUp等)都是客户端方法;列/行顺序持久化使用F.customEvent+Page_CustomEvent,结构化参数传 JSON 对象/数组。详见 advanced.md。 - 行命令统一用
RenderField.Commands:Pro、Core RazorForms 与 Java 都使用RenderField.Commands;Command只属于RenderField。客户端附加逻辑监听 Grid 的rowcommand,服务端声明OnRowCommand。
官方资源(Official Resources)
- 在线 API:
- JS:https://fineui.com/js/api/(`FineUI.Grid` /
FineUI.GridColumn) - Pro:https://fineui.com/pro/api/
- Core:https://fineui.com/core/api/
- JS:https://fineui.com/js/api/(`FineUI.Grid` /
- FineUI.Java:控件属性语义与 Core 一致(属性名 kebab-case、属性值同 Core),客户端 F.js API 与 JS 端完全相同;查属性时先看 Core API 再按命名约定转 kebab-case。
- 官网示例库与文档见 https://www.fineui.com/