Skip to content

Commit 0de6d62

Browse files
feat(module:tabs): support destroyInactiveTabPane input (#8845)
1 parent fbf8732 commit 0de6d62

8 files changed

+157
-88
lines changed

components/tabs/demo/guard.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
22
import { Observable } from 'rxjs';
33

4-
import { NzModalService } from 'ng-zorro-antd/modal';
4+
import { NzModalModule, NzModalService } from 'ng-zorro-antd/modal';
55
import { NzTabsCanDeactivateFn, NzTabsModule } from 'ng-zorro-antd/tabs';
66

77
@Component({
88
selector: 'nz-demo-tabs-guard',
99
standalone: true,
10-
imports: [NzTabsModule],
10+
imports: [NzTabsModule, NzModalModule],
1111
template: `
1212
<nz-tabset [nzCanDeactivate]="canDeactivate">
1313
@for (tab of tabs; track tab) {

components/tabs/demo/lazy.md

+7-3
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
---
22
order: 13
33
title:
4-
zh-CN: 懒加载
4+
zh-CN: 延迟加载
55
en-US: LazyLoad
66
---
77

88
## zh-CN
99

10-
默认情况下,`nz-tab` 中的组件的 `ngOnInit` 会提前触发,如果希望当 Tab 被激活时再触发 `ngOnInit`,可以使用该示例中的懒加载方式。
10+
默认情况下,`nz-tab` 中的组件是立即加载的。可以通过在 `ng-template` 中使用 `[nz-tab]` 指令来实现延迟加载选项卡内容。
11+
12+
> 配合 `nzDestroyInactiveTabPane` 使用,可以实现 tab 隐藏时销毁组件。
1113
1214
## en-US
1315

14-
By default, the contents in `nz-tab` are eagerly loaded. Tab contents can be lazy loaded by declaring the body in a `ng-template` with the `[nz-tab]` attribute.
16+
By default, the contents in `nz-tab` are eagerly loaded. Tab contents can be lazy loaded by declaring the body in a `ng-template` with the `[nz-tab]` directive.
17+
18+
> Combine with `nzDestroyInactiveTabPane` to destroy the component when the tab is hidden.

components/tabs/doc/index.en-US.md

+18-17
Original file line numberDiff line numberDiff line change
@@ -24,23 +24,24 @@ import { NzTabsModule } from 'ng-zorro-antd/tabs';
2424

2525
### nz-tabset:standalone
2626

27-
| Property | Description | Type | Default | Global Config |
28-
| ------------------------- | ----------------------------------------------------------------------------------------- | --------------------------------------------------- | ---------------------------------- | ------------- |
29-
| `[nzSelectedIndex]` | Current tab's index | `number` | - |
30-
| `[nzAnimated]` | Whether to change tabs with animation. Only works while `nzTabPosition="top" \| "bottom"` | `boolean \| {inkBar:boolean, tabPane:boolean}` | `true`, `false` when `type="card"` ||
31-
| `[nzSize]` | preset tab bar size | `'large' \| 'small' \| 'default'` | `'default'` ||
32-
| `[nzTabBarExtraContent]` | Extra content in tab bar | `TemplateRef<void>` | - |
33-
| `[nzTabBarStyle]` | Tab bar style object | `object` | - |
34-
| `[nzTabPosition]` | Position of tabs | `'top' \| 'right' \| 'bottom' \| 'left'` | `'top'` | |
35-
| `[nzType]` | Basic style of tabs | `'line' \| 'card' \| 'editable-card'` | `'line'` ||
36-
| `[nzTabBarGutter]` | The gap between tabs | `number` | - ||
37-
| `[nzHideAll]` | Whether hide all tabs | `boolean` | `false` |
38-
| `[nzLinkRouter]` | Link with Angular router. It supports child mode and query param mode | `boolean` | `false` | |
39-
| `[nzLinkExact]` | Use exact routing matching | `boolean` | `true` |
40-
| `[nzCanDeactivate]` | Determine if a tab can be deactivated | `NzTabsCanDeactivateFn` | - |
41-
| `[nzCentered]` | Centers tabs | `boolean` | `false` |
42-
| `(nzSelectedIndexChange)` | Current tab's index change callback | `EventEmitter<number>` | - |
43-
| `(nzSelectChange)` | Current tab's change callback | `EventEmitter<{index: number,tab: NzTabComponent}>` | - |
27+
| Property | Description | Type | Default | Global Config |
28+
| ---------------------------- | ----------------------------------------------------------------------------------------- | --------------------------------------------------- | ---------------------------------- | ------------- |
29+
| `[nzSelectedIndex]` | Current tab's index | `number` | - |
30+
| `[nzAnimated]` | Whether to change tabs with animation. Only works while `nzTabPosition="top" \| "bottom"` | `boolean \| {inkBar:boolean, tabPane:boolean}` | `true`, `false` when `type="card"` ||
31+
| `[nzSize]` | preset tab bar size | `'large' \| 'small' \| 'default'` | `'default'` ||
32+
| `[nzTabBarExtraContent]` | Extra content in tab bar | `TemplateRef<void>` | - |
33+
| `[nzTabBarStyle]` | Tab bar style object | `object` | - |
34+
| `[nzTabPosition]` | Position of tabs | `'top' \| 'right' \| 'bottom' \| 'left'` | `'top'` | |
35+
| `[nzType]` | Basic style of tabs | `'line' \| 'card' \| 'editable-card'` | `'line'` ||
36+
| `[nzTabBarGutter]` | The gap between tabs | `number` | - ||
37+
| `[nzHideAll]` | Whether hide all tabs | `boolean` | `false` |
38+
| `[nzLinkRouter]` | Link with Angular router. It supports child mode and query param mode | `boolean` | `false` | |
39+
| `[nzLinkExact]` | Use exact routing matching | `boolean` | `true` |
40+
| `[nzCanDeactivate]` | Determine if a tab can be deactivated | `NzTabsCanDeactivateFn` | - |
41+
| `[nzCentered]` | Centers tabs | `boolean` | `false` |
42+
| `[nzDestroyInactiveTabPane]` | Whether destroy inactive TabPane when change tab | `boolean` | `false` |
43+
| `(nzSelectedIndexChange)` | Current tab's index change callback | `EventEmitter<number>` | - |
44+
| `(nzSelectChange)` | Current tab's change callback | `EventEmitter<{index: number,tab: NzTabComponent}>` | - |
4445

4546
### nz-tabset[nzType="editable-card"]:standalone
4647

components/tabs/doc/index.zh-CN.md

+18-17
Original file line numberDiff line numberDiff line change
@@ -27,23 +27,24 @@ import { NzTabsModule } from 'ng-zorro-antd/tabs';
2727

2828
### nz-tabset:standalone
2929

30-
| 参数 | 说明 | 类型 | 默认值 | 全局配置 |
31-
| ------------------------- | ------------------------------------------------------------------ | --------------------------------------------------- | ------------------------------------- | -------- |
32-
| `[nzSelectedIndex]` | 当前激活 tab 面板的 序列号,可双向绑定 | `number` | - |
33-
| `[nzAnimated]` | 是否使用动画切换 Tabs,在 `nzTabPosition="top" \| "bottom"` 时有效 | `boolean \| {inkBar:boolean, tabPane:boolean}` | `true`, 当 `type="card"` 时为 `false` ||
34-
| `[nzSize]` | 大小,提供 `large` `default``small` 三种大小 | `'large' \| 'small' \| 'default'` | `'default'` ||
35-
| `[nzTabBarExtraContent]` | tab bar 上额外的元素 | `TemplateRef<void>` | - |
36-
| `[nzTabBarStyle]` | tab bar 的样式对象 | `object` | - |
37-
| `[nzTabPosition]` | 页签位置,可选值有 `top` `right` `bottom` `left` | `'top' \| 'right' \| 'bottom' \| 'left'` | `'top'` | |
38-
| `[nzType]` | 页签的基本样式 | `'line' \| 'card' \| 'editable-card'` | `'line'` ||
39-
| `[nzTabBarGutter]` | tabs 之间的间隙 | `number` | - ||
40-
| `[nzHideAll]` | 是否隐藏所有 tab 内容 | `boolean` | `false` |
41-
| `[nzLinkRouter]` | 与 Angular 路由联动 | `boolean` | `false` | |
42-
| `[nzLinkExact]` | 以严格匹配模式确定联动的路由 | `boolean` | `true` |
43-
| `[nzCanDeactivate]` | 决定一个 tab 是否可以被切换 | `NzTabsCanDeactivateFn` | - |
44-
| `[nzCentered]` | 标签居中展示 | `boolean` | `false` |
45-
| `(nzSelectedIndexChange)` | 当前激活 tab 面板的 序列号变更回调函数 | `EventEmitter<number>` | - |
46-
| `(nzSelectChange)` | 当前激活 tab 面板变更回调函数 | `EventEmitter<{index: number,tab: NzTabComponent}>` | - |
30+
| 参数 | 说明 | 类型 | 默认值 | 全局配置 |
31+
| ---------------------------- | ------------------------------------------------------------------ | --------------------------------------------------- | ------------------------------------- | -------- |
32+
| `[nzSelectedIndex]` | 当前激活 tab 面板的 序列号,可双向绑定 | `number` | - |
33+
| `[nzAnimated]` | 是否使用动画切换 Tabs,在 `nzTabPosition="top" \| "bottom"` 时有效 | `boolean \| {inkBar:boolean, tabPane:boolean}` | `true`, 当 `type="card"` 时为 `false` ||
34+
| `[nzSize]` | 大小,提供 `large` `default``small` 三种大小 | `'large' \| 'small' \| 'default'` | `'default'` ||
35+
| `[nzTabBarExtraContent]` | tab bar 上额外的元素 | `TemplateRef<void>` | - |
36+
| `[nzTabBarStyle]` | tab bar 的样式对象 | `object` | - |
37+
| `[nzTabPosition]` | 页签位置,可选值有 `top` `right` `bottom` `left` | `'top' \| 'right' \| 'bottom' \| 'left'` | `'top'` | |
38+
| `[nzType]` | 页签的基本样式 | `'line' \| 'card' \| 'editable-card'` | `'line'` ||
39+
| `[nzTabBarGutter]` | tabs 之间的间隙 | `number` | - ||
40+
| `[nzHideAll]` | 是否隐藏所有 tab 内容 | `boolean` | `false` |
41+
| `[nzLinkRouter]` | 与 Angular 路由联动 | `boolean` | `false` | |
42+
| `[nzLinkExact]` | 以严格匹配模式确定联动的路由 | `boolean` | `true` |
43+
| `[nzCanDeactivate]` | 决定一个 tab 是否可以被切换 | `NzTabsCanDeactivateFn` | - |
44+
| `[nzCentered]` | 标签居中展示 | `boolean` | `false` |
45+
| `[nzDestroyInactiveTabPane]` | 被隐藏时是否销毁 DOM 结构 | `boolean` | `false` |
46+
| `(nzSelectedIndexChange)` | 当前激活 tab 面板的 序列号变更回调函数 | `EventEmitter<number>` | - |
47+
| `(nzSelectChange)` | 当前激活 tab 面板变更回调函数 | `EventEmitter<{index: number,tab: NzTabComponent}>` | - |
4748

4849
### nz-tabset[nzType="editable-card"]:standalone
4950

components/tabs/tab-body.component.ts

+3-28
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,7 @@
44
*/
55

66
import { NgTemplateOutlet } from '@angular/common';
7-
import {
8-
ChangeDetectionStrategy,
9-
Component,
10-
Input,
11-
OnChanges,
12-
SimpleChanges,
13-
TemplateRef,
14-
ViewEncapsulation
15-
} from '@angular/core';
7+
import { ChangeDetectionStrategy, Component, Input, TemplateRef, ViewEncapsulation } from '@angular/core';
168

179
import { tabSwitchMotion } from 'ng-zorro-antd/core/animation';
1810

@@ -22,11 +14,7 @@ import { tabSwitchMotion } from 'ng-zorro-antd/core/animation';
2214
preserveWhitespaces: false,
2315
encapsulation: ViewEncapsulation.None,
2416
changeDetection: ChangeDetectionStrategy.OnPush,
25-
template: `
26-
@if (hasBeenActive || forceRender) {
27-
<ng-template [ngTemplateOutlet]="content"></ng-template>
28-
}
29-
`,
17+
template: ` <ng-template [ngTemplateOutlet]="content"></ng-template> `,
3018
host: {
3119
class: 'ant-tabs-tabpane',
3220
'[class.ant-tabs-tabpane-active]': 'active',
@@ -41,21 +29,8 @@ import { tabSwitchMotion } from 'ng-zorro-antd/core/animation';
4129
standalone: true,
4230
animations: [tabSwitchMotion]
4331
})
44-
export class NzTabBodyComponent implements OnChanges {
32+
export class NzTabBodyComponent {
4533
@Input() content: TemplateRef<void> | null = null;
4634
@Input() active = false;
4735
@Input() animated = true;
48-
@Input() forceRender = false;
49-
50-
/**
51-
* If this tab is ever activated, then the content should always be rendered.
52-
*/
53-
protected hasBeenActive = false;
54-
55-
ngOnChanges(changes: SimpleChanges): void {
56-
const { active } = changes;
57-
if (active?.currentValue) {
58-
this.hasBeenActive = true;
59-
}
60-
}
6136
}

components/tabs/tab.component.ts

+9
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,11 @@ export class NzTabComponent implements OnChanges, OnDestroy {
6464
@ViewChild('contentTemplate', { static: true }) contentTemplate!: TemplateRef<NzSafeAny>;
6565

6666
isActive: boolean = false;
67+
hasBeenActive = false;
6768
position: number | null = null;
6869
origin: number | null = null;
6970
closestTabSet = inject(NZ_TAB_SET);
71+
7072
readonly stateChanges = new Subject<void>();
7173

7274
get content(): TemplateRef<NzSafeAny> {
@@ -87,4 +89,11 @@ export class NzTabComponent implements OnChanges, OnDestroy {
8789
ngOnDestroy(): void {
8890
this.stateChanges.complete();
8991
}
92+
93+
setActive(active: boolean): void {
94+
this.isActive = active;
95+
if (active) {
96+
this.hasBeenActive = true;
97+
}
98+
}
9099
}

0 commit comments

Comments
 (0)