news 2026/9/29 8:03:02

ng-zorro-antd 表格动态控制(Table Dynamic Settings)实战:用 Form 表单实时切换全部表格属性

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ng-zorro-antd 表格动态控制(Table Dynamic Settings)实战:用 Form 表单实时切换全部表格属性
  • UI组件
  • 前端

【免费下载链接】ng-zorro-antd

Angular UI Component Library based on Ant Design

项目地址:https://gitcode.com/gh_mirrors/ng/ng-zorro-antd
点击查看免费下载

本文以 ng-zorro-antd 官方演示Dynamic Settings(动态控制表格属性)为核心,完整拆解其"表单配置面板 + 响应式表格渲染"的实现方案。演示位于 components/table/demo/dynamic-settings.md(说明文档)与 components/table/demo/dynamic-settings.ts(源码实现),读者读完可以掌握如何通过ReactiveFormsModule的FormGroup与 Angular signals 驱动nz-table的十余个输入属性,在运行期实时切换边框、分页、固定列、表头、加载态、尺寸等配置,并独立复刻出这一"配置组合预览器"。

一、演示主题:选择不同配置组合查看效果

官方对该演示的定位非常精炼,中文说明为"选择不同配置组合查看效果",英文为"Select different settings to see the result"。虽然说明只有一句话,但其背后的实现承载了nz-table绝大多数可动态调节的属性:

  • 外观类:bordered(边框)、size(表格尺寸)、loading(加载态);
  • 结构类:title(标题)、header(列头)、footer(表尾)、expandable(展开行);
  • 数据类:pagination(前端分页开关)、sizeChanger(每页条数切换器)、simple(简单分页)、position(分页位置)、paginationType(分页尺寸);
  • 交互类:checkbox(行多选)、ellipsis(单元格省略)、fixHeader(固定表头)、tableScroll(横向/固定滚动与固定列)。

整个演示可以看作一个"表格属性实验台":左侧(上方)是一排开关与单选组,右侧(下方)是实时响应这些设置的表格。下面从源码逐层还原其实现。

二、配置面板的骨架:Setting 接口与表单初始化

演示把所有可配置项收敛进一个强类型接口Setting,定义见 components/table/demo/dynamic-settings.ts:

type TableScroll = 'unset' | 'scroll' | 'fixed'; interface Setting { bordered: boolean; loading: boolean; pagination: boolean; sizeChanger: boolean; title: boolean; header: boolean; footer: boolean; expandable: boolean; checkbox: boolean; fixHeader: boolean; noResult: boolean; ellipsis: boolean; simple: boolean; size: NzTableSize; tableScroll: TableScroll; tableLayout: NzTableLayout; position: NzTablePaginationPosition; paginationType: NzTablePaginationType; }

这些枚举类型全部来自组件自身的类型定义 components/table/src/table.types.ts:

export type NzTableLayout = 'fixed' | 'auto'; export type NzTablePaginationPosition = 'top' | 'bottom' | 'both'; export type NzTablePaginationType = 'default' | 'small'; export type NzTableSize = 'middle' | 'default' | 'small';

也就是说:表格尺寸只有middle / default / small三种;分页位置可选top / bottom / both;分页类型仅default / small;表格布局仅fixed / auto。配置面板中"Size、Pagination Position、Pagination Type、Table Layout"四组单选的可选值,正是这些类型的字面量全集。

表单通过NonNullableFormBuilder构造,并为每个控件给出演示用的默认值(源码第 155-174 行):

readonly settingForm: FormGroup<{ [K in keyof Setting]: FormControl<Setting[K]> }> = this.formBuilder.group({ bordered: [false], loading: [false], pagination: [true], sizeChanger: [false], title: [true], header: [true], footer: [true], expandable: [true], checkbox: [true], fixHeader: [false], noResult: [false], ellipsis: [false], simple: [false], size: 'small' as NzTableSize, paginationType: 'default' as NzTablePaginationType, tableScroll: 'unset' as TableScroll, tableLayout: 'auto' as NzTableLayout, position: 'bottom' as NzTablePaginationPosition });

三、面板 UI:开关组与单选组的声明式渲染

面板模板使用@for循环统一渲染两组控件(源码第 54-77 行):

  • listOfSwitch:13 个nz-switch,每个开关绑定一个布尔型formControlName,例如Bordered、Loading、Pagination、PageSizeChanger、Title、Column Header、Footer、Expandable、Checkbox、Fixed Header、No Result、Ellipsis、Simple Pagination;
  • listOfRadio:5 组nz-radio-group(按钮样式nz-radio-button),对应Size、Table Scroll、Table Layout、Pagination Position、Pagination Type。
<form nz-form nzLayout="inline" [formGroup]="settingForm"> @for (item of listOfSwitch; track item) { <nz-form-item> <nz-form-label>{{ item.name }}</nz-form-label> <nz-form-control> <nz-switch [formControlName]="item.formControlName" /> </nz-form-control> </nz-form-item> } @for (radio of listOfRadio; track radio) { <nz-form-item> <nz-form-label>{{ radio.name }}</nz-form-label> <nz-form-control> <nz-radio-group [formControlName]="radio.formControlName"> @for (o of radio.listOfOption; track o) { <label nz-radio-button [nzValue]="o.value">{{ o.label }}</label> } </nz-radio-group> </nz-form-control> </nz-form-item> } </form>

这种"配置元数据数组"的做法把 13 个开关、5 组单选收敛成两份纯数据,模板零重复,新增配置项只需往数组里加一条记录——这是本演示最值得借鉴的工程模式。

四、表格模板:nz-table 输入属性与单元格增强语法

表格部分(源码第 78-143 行)把settingForm的当前值经settingValue()signal 逐项绑定到nz-table:

<nz-table #dynamicTable [nzScroll]="{ x: scrollX(), y: scrollY() }" [nzData]="listOfData()" [nzTableLayout]="settingValue().tableLayout" [nzBordered]="settingValue().bordered" [nzSimple]="settingValue().simple" [nzLoading]="settingValue().loading" [nzPaginationType]="settingValue().paginationType" [nzPaginationPosition]="settingValue().position" [nzShowSizeChanger]="settingValue().sizeChanger" [nzFrontPagination]="settingValue().pagination" [nzShowPagination]="settingValue().pagination" [nzFooter]="settingValue().footer ? 'Here is Footer' : null" [nzTitle]="settingValue().title ? 'Here is Title' : null" [nzSize]="settingValue().size" (nzCurrentPageDataChange)="currentPageDataChange($event)" >

各输入属性在官方 API 文档 components/table/doc/index.zh-CN.md 与 components/table/doc/index.en-US.md 中有完整定义,与本演示的对应关系如下:

演示控件nz-table 属性类型默认值说明
Bordered[nzBordered]booleanfalse是否展示外边框和列边框
Loading[nzLoading]booleanfalse页面是否加载中(可配nzLoadingDelay防闪烁)
Pagination[nzFrontPagination]/[nzShowPagination]booleantrue/true是否前端分页、是否显示分页器
PageSizeChanger[nzShowSizeChanger]booleanfalse是否可以改变nzPageSize(选项默认[10, 20, 30, 40])
Title[nzTitle]string \| TemplateRef<void>-表格标题
Footer[nzFooter]string \| TemplateRef<void>-表格尾部
Fixed Header[nzScroll].yobject-纵向滚动即固定表头
No Result[nzData]置空T[]-无数据时展示空状态
Ellipsis[nzEllipsis](th/td)booleanfalse单元格内容省略,仅在nzTableLayout = 'fixed'时生效
Simple Pagination[nzSimple]boolean-简单分页
Size[nzSize]'middle' \| 'small' \| 'default''default'表格尺寸
Table Layout[nzTableLayout]'fixed' \| 'auto''auto'表格布局,fixed是nzEllipsis生效的前提
Pagination Position[nzPaginationPosition]'top' \| 'bottom' \| 'both''bottom'分页显示位置
Pagination Type[nzPaginationType]'default' \| 'small''default'分页尺寸

注意[nzTitle]与[nzFooter]的写法:settingValue().title ? 'Here is Title' : null,即传入null时关闭对应区域,传入字符串时渲染文本(二者也支持TemplateRef自定义复杂内容)。

单元格层面用到了三组增强指令(演示第 96-142 行):

  • 固定列:[nzLeft]="fixedColumn()"(左侧固定列)与[nzRight]="fixedColumn()"(右侧固定 Action 列),fixedColumn()为boolean时由组件自动计算像素宽度;
  • 展开行:<td [(nzExpand)]="data.expand">双向绑定展开状态,配合<tr [nzExpand]="data.expand">渲染展开内容;
  • 行多选:表头[nzChecked]="allChecked()"、[nzIndeterminate]="indeterminate()"与(nzCheckedChange)="checkAll($event)",行单元格[(nzChecked)]="data.checked"双向绑定。

五、数据与选择状态管理:signals + 当前页数据回填

演示用 Angular 16+ 的 signal 承载全部运行期状态(源码第 175-182 行):

readonly listOfData = signal<readonly ItemData[]>([]); // 全量数据 readonly displayData = signal<readonly ItemData[]>([]); // 当前页数据 readonly allChecked = signal(false); // 表头全选状态 readonly indeterminate = signal(false); // 半选状态 readonly fixedColumn = signal(false); // 是否固定首尾列 readonly scrollX = signal<string | null>(null); // 横向滚动宽度 readonly scrollY = signal<string | null>(null); // 纵向滚动高度 readonly settingValue = signal(this.settingForm.value as Setting); // 配置快照

关键联动是(nzCurrentPageDataChange)事件:表格当前页数据变化时写回displayData并刷新勾选状态(源码第 244-255 行):

currentPageDataChange($event: readonly ItemData[]): void { this.displayData.set($event); this.refreshStatus(); } refreshStatus(): void { const validData = this.displayData().filter(value => !value.disabled); const allChecked = validData.length > 0 && validData.every(value => value.checked); const allUnChecked = validData.every(value => !value.checked); this.allChecked.set(allChecked); this.indeterminate.set(!allChecked && !allUnChecked); }

全选/取消全选只作用于当前页displayData(并跳过disabled行),这是分页表格多选的正确姿势——避免跨页误操作;indeterminate半选状态在"部分选中且部分未选"时为true:

checkAll(value: boolean): void { this.displayData().forEach(data => { if (!data.disabled) { data.checked = value; } }); this.refreshStatus(); }

测试数据由generateData()生成 100 条记录(源码第 266-280 行),字段覆盖演示所需:checked(勾选)、expand(展开)、description(展开内容)、age/address(普通单元格,Address 用于验证nzEllipsis省略效果)。

六、联动订阅:tableScroll、fixHeader 与 noResult 的副作用

演示最具"动态"精髓的是三个valueChanges订阅(源码第 282-301 行),它们把表单控件的变化翻译成表格的具体行为:

ngOnInit(): void { // 1. 全量配置快照:任何表单变化都刷新 settingValue this.settingForm.valueChanges.subscribe(value => { this.settingValue.set(value as Setting); }); // 2. Table Scroll 三态联动:unset / scroll / fixed this.settingForm.controls.tableScroll.valueChanges.subscribe(scroll => { this.fixedColumn.set(scroll === 'fixed'); // fixed 时固定左右列 this.scrollX.set(scroll === 'scroll' || scroll === 'fixed' ? '100vw' : null); // 横向滚动 }); // 3. Fixed Header:开启后给表格纵向滚动高度 240px,即固定表头 this.settingForm.controls.fixHeader.valueChanges.subscribe(fixed => { this.scrollY.set(fixed ? '240px' : null); }); // 4. No Result:清空/恢复数据以演示空状态 this.settingForm.controls.noResult.valueChanges.subscribe(empty => { if (empty) { this.listOfData.set([]); } else { this.listOfData.set(this.generateData()); } }); this.listOfData.set(this.generateData()); }

其中第 2 处值得展开:Table Scroll单选有Unset / Scroll / Fixed三档——scroll仅开启横向滚动(nzScroll.x = '100vw'),fixed在横向滚动基础上再通过[nzLeft]/[nzRight]固定 Name 列与 Action 列,形成"横向滚动 + 首尾固定列"的经典复杂表格布局;而nzScroll.y = '240px'固定表头则被独立成Fixed Header开关,二者互不干扰、可自由组合。

另外注意settingForm的泛型写法FormGroup<{ [K in keyof Setting]: FormControl<Setting[K]> }>——它利用映射类型让每个控件的类型与Setting字段严格对齐,是 TypeScript 强类型表单的模板级示范;NonNullableFormBuilder保证默认值非空。

七、性能与变更检测提示

官方文档 components/table/doc/index.en-US.md 的 Note 一节专门提醒:NG-ZORRO 组件全部运行在 OnPush 变更检测策略下,直接修改传入@Input()的数组/对象不会触发视图更新,应使用不可变方式更新数据(演示中正是依赖signal.set()与@for ... track data.id保证引用变更可被检测):

// 新增数据:使用展开运算符生成新数组 this.dataSet = [...this.dataSet, newItem]; // 删除数据:使用 filter 生成新数组 this.dataSet = this.dataSet.filter(d => d.key !== key);

八、如何在本仓库中复现与继续研究

  • 演示说明:查看 components/table/demo/dynamic-settings.md;
  • 完整实现:阅读 components/table/demo/dynamic-settings.ts,其中组件依赖ReactiveFormsModule、NzFormModule、NzRadioModule、NzSwitchModule、NzDividerModule与NzTableModule,引入这些模块后即可在任意页面复刻;
  • 类型定义:NzTableSize、NzTableLayout、NzTablePaginationPosition、NzTablePaginationType等枚举见 components/table/src/table.types.ts;
  • API 全表:nz-table、th、td、thead、tr、tfoot的全部输入输出属性见 components/table/doc/index.zh-CN.md 与 components/table/doc/index.en-US.md;
  • 组件核心实现:nz-table主体位于components/table/src/table/目录(含table.component.ts、table-inner-default.component.ts等),table-data.service.ts负责分页/排序/筛选的数据加工管线,是理解"前端分页nzFrontPagination"底层机制的最佳入口。

小结

Dynamic Settings演示虽小,却是理解nz-table输入属性的"活字典":一份Setting接口、一份表单、两份配置元数据数组、四条valueChanges订阅,就串起了边框、加载、分页、尺寸、布局、滚动、固定列/表头、展开行、多选、省略、空状态等几乎全部核心能力。把它的"配置元数据 + 强类型表单 + signal 快照"模式迁移到自己的业务中,即可低成本打造"表格设置中心"或调试面板,快速验证任意属性组合下的表现。

  • UI组件
  • 前端

【免费下载链接】ng-zorro-antd

Angular UI Component Library based on Ant Design

项目地址:https://gitcode.com/gh_mirrors/ng/ng-zorro-antd
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/29 8:03:02

Paperclip协议:AI Agent三端通信的轻量级HTTP协议栈

1. “Paperclip”不是回形针&#xff1a;它是一套面向AI原生应用的轻量级协议栈最近在几个技术社区里频繁看到“paperclip”这个词&#xff0c;尤其和Node.js、React、OpenClaw、Claude这些词高频共现。一开始我也以为是某个UI组件库——毕竟React生态里叫“clip”“paper”“c…

作者头像 李华
网站建设 2026/9/29 8:01:27

Hermes Agent 安装失败自救:9 个阶段、3 份日志、5 步恢复

Hermes Agent 安装失败自救&#xff1a;9 个阶段、3 份日志、5 步恢复 【免费下载链接】hermes-agent The agent that grows with you 项目地址: https://gitcode.com/GitHub_Trending/he/hermes-agent Hermes Agent 是 Nous Research 出品的自进化 AI 智能体——从执行…

作者头像 李华
网站建设 2026/9/29 7:58:14

TLS 1.3新握手协议的前向安全审计实战解析

做安全审计做了这么多年&#xff0c;每年都要在各种报告里反复写SSL/TLS握手协议、前向安全这几个词。这次拿到这个《SSL/TLS 3.0新握手协议的前向安全审计研究报告》标题&#xff0c;我第一反应是&#xff1a;这个主题终于有人愿意往深里挖了。你可能也注意到了&#xff0c;网…

作者头像 李华