
UI组件前端【免费下载链接】ng-zorro-antdAngular UI Component Library based on Ant Design项目地址https://gitcode.com/gh_mirrors/ng/ng-zorro-antd点击查看免费下载导读表格编辑是后台管理系统中最高频的交互场景之一。NG-ZORROng-zorro-antd官方在 Table 组件的演示集中提供了可编辑单元格Editable Cells示例它展示了如何在保持组件高性能的前提下以极简代码实现点击单元格进入编辑态、失焦保存、支持新增与删除行的完整闭环。本文以该演示为骨架结合nz-table组件的源码实现讲清楚三个关键问题如何在 OnPush 变更检测策略下安全地修改表格数据、如何用 signal 管理编辑状态、以及如何把该方案扩展为行编辑或自定义编辑形态。读完本文你将能直接复制这套模式到自己的业务表格中。一、示例总体设计以最小代码实现单元格编辑闭环官方演示见 edit-cell.ts的核心思路非常直白不引入任何复杂的编辑框架用文本与输入框互斥显隐来模拟编辑状态。整个示例只依赖 Angular 自身的表单绑定与 NG-ZORRO 的三个模块imports: [FormsModule, NzButtonModule, NzInputModule, NzPopconfirmModule, NzTableModule]FormsModule提供ngModel双向绑定让输入框直接修改数据行对象NzButtonModule渲染Add新增按钮NzInputModule提供nz-input指令的输入框样式NzPopconfirmModule为Delete操作提供二次确认气泡NzTableModule表格本体。数据模型是一个普通的接口对象interface ItemData { id: string; name: string; age: string; address: string; }模板中的核心交互段落如下td div classeditable-cell [hidden]editId() data.id (click)startEdit(data.id) {{ data.name }} /div input [hidden]editId() ! data.id typetext nz-input [(ngModel)]data.name (blur)stopEdit() / /td当editId()当前正在编辑行的 id不等于该行 id 时显示文本 div点击后调用startEdit(data.id)输入框解除隐藏、接管编辑输入框失焦blur时调用stopEdit()关闭编辑态。由于输入框通过ngModel直接双向绑定到data.name失焦时数据已经写回数据行因此不需要额外的保存动作。二、OnPush 模式下的数据操作铁律immutable 更新演示文档edit-cell.md特别强调了一条 NG-ZORRO 的全局约束为了获得更好的性能NG-ZORRO 所有组件都运行在 OnPush 模式下这意味着对Input()数据的 mutate 将不会生效请使用 immutable 方式操作数组或者对象。这是整个示例最容易踩坑的地方值得拆开讲透。2.1 为什么 mutate 不生效nz-table组件在 table.component.ts 中声明了Input() nzData: readonly T[] []并在ngOnChanges中把新数据推入内部数据服务if (nzData) { this.nzData this.nzData || []; this.nzTableDataService.updateListOfData(this.nzData); }OnPush 策略下Angular 只在Input()引用发生变化、事件触发或显式markForCheck时才检查组件。如果你直接list.push(newItem)或item.name xxxnzData的引用没有变ngOnChanges不会被触发表格拿到的仍是旧数组引用界面自然不刷新。这也就是演示代码里反复使用展开运算符创建新数组/新对象的根本原因。2.2 示例中的三处 immutable 操作演示组件用signal持有数据全部通过update回调以纯函数方式生成新值新增行addRowaddRow(): void { this.listOfData.update(listOfData [ ...listOfData, { id: ${this.i}, name: Edward King ${this.i}, age: 32, address: London, Park Lane no. ${this.i} } ]); this.i; }删除行deleteRowdeleteRow(id: string): void { this.listOfData.update(listOfData listOfData.filter(d d.id ! id)); }编辑时ngModel写入的是data.name这个对象属性虽然这看起来像 mutate但编辑的是从nzData派生的当前页数据行而刷新表格整体数据依赖的是数组引用的变化编辑态显隐则完全由editId这个 signal 驱动不依赖数据变更检测。这正是该方案能在 OnPush 下稳定工作的关键设计。三、编辑状态管理signal 替代组件字段演示组件用两个 signal 管理全部状态见 edit-cell.tsreadonly editId signalstring | null(null); readonly listOfData signalItemData[]([]);editId当前编辑行的 idnull表示未处于编辑态。点击单元格startEdit(id)将其设为 id失焦stopEdit()将其重置为nulllistOfData表格数据源模板中通过listOfData()读取。在模板中读取 signal 时如editId() data.id、[nzData]listOfData()Angular 会自动把 signal 的读取注册为依赖signal 值变化时精准触发对应视图更新——这比手动维护editingId字段 ChangeDetectorRef更加简洁也天然符合 immutable 的更新风格。四、与 nz-table 数据管线的衔接理解了nzData的语义就能明白示例中另一个关键写法——为什么模板遍历的是editRowTable.data而不是listOfData()nz-table #editRowTable nzBordered [nzData]listOfData() ... for (data of editRowTable.data; track data.id) {nz-table组件声明了exportAs: nzTable见 table.component.ts模板引用变量#editRowTable拿到的是组件实例其data属性是经过分页、排序、筛选处理后的当前页数据。遍历editRowTable.data而不是原始nzData保证在开启分页时也只渲染当前页的行。数据流的底层实现在 table-data.service.tsupdateListOfData()把新数组推入listOfData$BehaviorSubject随后经过listOfDataAfterCalc$筛选/排序与listOfFrontEndCurrentPageData$分页切片两级变换最终通过listOfCurrentPageData$暴露给表格渲染。整个链路都是响应式流任何一步替换新数组都会触发下游重算——这从源码层面再次印证了必须传新引用的必要性。五、交互细节与样式增强5.1 删除确认删除操作通过nz-popconfirm包裹避免误删a nz-popconfirm nzPopconfirmTitleSure to delete? (nzOnConfirm)deleteRow(data.id)Delete/anzOnConfirm是确认后的回调只有用户点击确认才执行deleteRow。5.2 编辑态的视觉反馈示例自带的样式让可编辑这一状态变得可见edit-cell.ts 内联 styles.editable-cell { position: relative; padding: 5px 12px; cursor: pointer; } .editable-row:hover .editable-cell { border: 1px solid #d9d9d9; border-radius: 4px; padding: 4px 11px; }默认状态下文本单元格带手型光标鼠标悬停行时可编辑单元格出现 1px 边框模拟点击进入编辑的暗示与 antd 设计语言保持一致。5.3 表格边框与 trackBynz-table nzBordered开启边框线便于单元格区分for ... track data.id指定唯一跟踪键避免增删行时 Angular 复用错误的 DOM 节点。六、进阶扩展从单元格编辑到行编辑同一演示集还提供了可编辑行Editable Rows方案见 edit-row.ts 与 edit-row.md与单元格编辑形成互补单元格编辑聚焦单个字段用editId标记当前编辑行适合字段少、改动小的场景行编辑用一个editCachesignal 存储{ [key]: { edit: boolean; data: ItemData } }为每行缓存一份编辑副本点击 Edit 后整行切换为输入框Save 时listOfData.update(list list.map(item item.id id ? { ...item, ...edited } : item))合并回数据源Cancel 时从缓存恢复原始副本。两者的共同点正是本文反复强调的 immutable 原则编辑副本独立于数据源、保存时生成新数组、取消时丢弃副本。开发者可以参照这两个例子把nz-input换成nz-select、nz-date-picker、nz-input-number等任意 NG-ZORRO 表单组件自由定制自己的编辑形态演示文档原文即注明开发者可以参照该例子根据自己需求自由定制表格的编辑功能。七、完整可运行代码以下是单元格编辑方案的完整组件代码来自 edit-cell.ts可直接复制到独立*.ts文件并在imports中引入对应模块后运行import { Component, OnInit, signal } from angular/core; import { FormsModule } from angular/forms; import { NzButtonModule } from ng-zorro-antd/button; import { NzInputModule } from ng-zorro-antd/input; import { NzPopconfirmModule } from ng-zorro-antd/popconfirm; import { NzTableModule } from ng-zorro-antd/table; interface ItemData { id: string; name: string; age: string; address: string; } Component({ selector: nz-demo-table-edit-cell, imports: [FormsModule, NzButtonModule, NzInputModule, NzPopconfirmModule, NzTableModule], template: button nz-button (click)addRow() nzTypeprimaryAdd/button br / br / nz-table #editRowTable nzBordered [nzData]listOfData() thead tr th nzWidth30%Name/th thAge/th thAddress/th thAction/th /tr /thead tbody for (data of editRowTable.data; track data.id) { tr classeditable-row td div classeditable-cell [hidden]editId() data.id (click)startEdit(data.id) {{ data.name }} /div input [hidden]editId() ! data.id typetext nz-input [(ngModel)]data.name (blur)stopEdit() / /td td{{ data.age }}/td td{{ data.address }}/td td a nz-popconfirm nzPopconfirmTitleSure to delete? (nzOnConfirm)deleteRow(data.id)Delete/a /td /tr } /tbody /nz-table , styles: .editable-cell { position: relative; padding: 5px 12px; cursor: pointer; } .editable-row:hover .editable-cell { border: 1px solid #d9d9d9; border-radius: 4px; padding: 4px 11px; } }) export class NzDemoTableEditCellComponent implements OnInit { i 0; readonly editId signalstring | null(null); readonly listOfData signalItemData[]([]); startEdit(id: string): void { this.editId.set(id); } stopEdit(): void { this.editId.set(null); } addRow(): void { this.listOfData.update(listOfData [ ...listOfData, { id: ${this.i}, name: Edward King ${this.i}, age: 32, address: London, Park Lane no. ${this.i} } ]); this.i; } deleteRow(id: string): void { this.listOfData.update(listOfData listOfData.filter(d d.id ! id)); } ngOnInit(): void { this.addRow(); this.addRow(); } }八、实践要点总结数据更新必须走 immutable新增用[...list, item]删除用filter修改行用map生成新对象任何push、splice、item.x y式的 mutate 在 OnPush 下都不会刷新表格编辑态与数据分离用editId或editCache这类 signal 单独驱动编辑 UI避免把 UI 状态混进业务数据遍历当前页数据通过模板引用变量#editRowTable访问data获取分页/排序后的当前页数据而不是直接遍历nzData失焦即保存ngModel绑定 blur关闭编辑态的组合天然实现所见即所得的保存体验按场景选形态单字段小改动用单元格编辑整行多字段用行编辑参照 edit-row.ts再进一步可用nz-select、nz-date-picker等替换输入框扩展为任意自定义编辑控件。相关源码路径索引演示说明文档edit-cell.md、edit-row.md演示实现edit-cell.ts、edit-row.ts表格组件实现table.component.tsnzData输入、exportAs: nzTable、ngOnChanges数据同步数据管线服务table-data.service.tsupdateListOfData与分页/排序/筛选响应式流赞分享UI组件前端【免费下载链接】ng-zorro-antdAngular UI Component Library based on Ant Design项目地址https://gitcode.com/gh_mirrors/ng/ng-zorro-antd点击查看免费下载相关推荐Ant Design Table 单元格编辑实战基于 Form 与 components 定制实现可编辑表格Ant Design Table 单元格编辑实战基于 Form 与 components 定制实现可编辑表格 本指南围绕 ant design 仓库中 edi前端UI组件设计系统Ant Design表格编辑功能单元格编辑与行内编辑实现Ant Design表格编辑功能单元格编辑与行内编辑实现 在日常数据管理工作中你是否经常遇到需要快速修改表格数据的场景比如编辑订单信息、更新用户资料或调整前端UI组件设计系统ng-zorro-antd Drawer 对象编辑实战用遮罩禁闭、自定义页脚构建可编辑表单抽屉ng zorro antd Drawer 对象编辑实战用遮罩禁闭、自定义页脚构建可编辑表单抽屉 本文围绕 ng zorro antdNG ZORRO官方示UI组件前端创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考