ng-zorro-antd 21.3.0 刚刚落地,这次更新集中在 Cascader(级联选择)组件上——补上了 nzPopupRender 属性,并把 Open 受控行为与 Ant Design React 版对齐。对于做中后台表单的开发者来说,这两个改动直接解决了之前"弹层里塞自定义内容要 hack"和"手动控制展开状态行为不一致"的老问题。
nzPopupRender:弹层里终于能放自定义内容
之前想在级联选择的弹出面板里加个搜索框、统计信息或操作按钮,要么用 ng-template 配合内部 API 绞尽脑汁,要么干脆放弃。21.3.0 新增的 nzPopupRender 属性,让你直接往弹层底部追加自定义模板,用法和 Ant Design React 版的 dropdownRender 一脉相承。
核心用法:
// app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-cascader-demo',
template: `
<nz-cascader
[nzOptions]="options"
[nzPopupRender]="popupFooter"
[(ngModel)]="selectedValue"
nzPlaceHolder="请选择地区"
></nz-cascader>
<ng-template #popupFooter>
<div class="popup-footer" style="padding: 8px 12px; border-top: 1px solid #f0f0f0;">
<button nz-button nzSize="small" nzType="link" (click)="clearSelection()">
清空选择
</button>
<span style="float: right; color: #999; font-size: 12px;">
共 {{ options.length }} 个省份
</span>
</div>
</ng-template>
`
})
export class CascaderDemoComponent {
selectedValue: string[] | null = null;
options = [
{
value: 'zhejiang',
label: '浙江',
children: [
{ value: 'hangzhou', label: '杭州', children: [{ value: 'xihu', label: '西湖' }] },
{ value: 'ningbo', label: '宁波' }
]
},
{
value: 'jiangsu',
label: '江苏',
children: [
{ value: 'nanjing', label: '南京' },
{ value: 'suzhou', label: '苏州' }
]
}
];
clearSelection(): void {
this.selectedValue = null;
}
}
几个注意点:
nzPopupRender接收的是ng-template引用,不是字符串或组件。- 自定义内容追加在级联面板底部,不会覆盖原有的列结构。
- 样式上建议用 Ant Design 的间距和分割线变量(
#f0f0f0、8px 12px),保持视觉一致。
Open 受控行为对齐:不再有"关不掉"的尴尬
之前 Angular 版 Cascader 的 nzOpen 受控行为和 React 版不一致——你设了 nzOpen 为 false,面板可能还是不收起,或者双向绑定的时机不对。21.3.0 把这块逻辑对齐到了 Ant Design 的规范:当你显式绑定 nzOpen,组件就完全由你控制展开/收起状态。
典型场景:表单联动,选择某个选项后自动收起面板,或者根据外部条件强制展开。
// controlled-open.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-controlled-cascader',
template: `
<nz-cascader
[nzOptions]="options"
[(ngModel)]="selectedValue"
[nzOpen]="isCascaderOpen"
(nzOpenChange)="onOpenChange($event)"
nzPlaceHolder="选择后自动收起"
></nz-cascader>
<button nz-button (click)="forceOpen()" style="margin-left: 12px;">
外部触发展开
</button>
`
})
export class ControlledCascaderComponent {
selectedValue: string[] | null = null;
isCascaderOpen = false;
options = [
{ value: 'beijing', label: '北京', children: [{ value: 'haidian', label: '海淀' }] },
{ value: 'shanghai', label: '上海', children: [{ value: 'pudong', label: '浦东' }] }
];
onOpenChange(open: boolean): void {
// 用户点击了面板外部或选择了叶子节点,面板请求收起
this.isCascaderOpen = open;
}
forceOpen(): void {
this.isCascaderOpen = true;
}
}
对齐后的行为要点:
| 场景 | 之前的行为 | 对齐后的行为 |
|---|---|---|
nzOpen=false 绑定 |
面板可能仍可见 | 面板立即收起 |
| 用户选完叶子节点 | nzOpenChange 不一定触发 |
正常触发 false,你决定是否收起 |
外部强制 nzOpen=true |
需要额外 hack | 直接生效 |
关键提醒:受控模式下,你必须处理 nzOpenChange 事件来更新 nzOpen 的值,否则面板状态会"卡住"。这是所有受控组件的通用规则,不只是 Cascader。
升级实操
从 20.x 或更早版本升级到 21.3.0,步骤很简单:
# 1. 确认 Angular 版本——ng-zorro 21.x 对应 Angular 17+
ng version
# 2. 更新 ng-zorro-antd
npm install ng-zorro-antd@21.3.0
# 3. 如果用了 Cascader,检查以下两点:
# - 有没有手动 hack 弹层内容的代码 → 改用 nzPopupRender
# - 有没有 nzOpen 双向绑定 [(nzOpen)] → 改为单向 [nzOpen] + (nzOpenChange)
升级检查清单:
- ✅ Cascader 的
nzOpen如果用了双向绑定[(nzOpen)],拆成单向受控 + 事件处理。 - ✅ 任何通过 CSS hack 或 overlay 直接操作弹层 DOM 的代码,迁移到
nzPopupRender。 - ✅ 其他组件无破坏性变更,正常升级即可。
- ✅ MIT 协议不变,企业项目无需额外授权。
ng-zorro-antd 21.3.0 的改动不大但很精准——Cascader 的两个痛点一次性解决。如果你的中后台项目里有级联选择器,这次升级值得立刻做。