• Transfer穿梭框
    • 何时使用
    • 单独引入此组件
    • 代码演示
    • API
      • nz-transfercomponent
        • TransferItem
        • TransferCanMove
        • TransferChange
        • TransferSearchChange
        • nzRenderList

    Transfer穿梭框

    双栏穿梭选择框。

    何时使用

    用直观的方式在两栏中移动元素,完成选择行为。

    选择一个或以上的选项后,点击对应的方向键,可以把选中的选项移动到另一栏。其中,左边一栏为 source,右边一栏为 target,API 的设计也反映了这两个概念。

    单独引入此组件

    想要了解更多关于单独引入组件的内容,可以在快速上手页面进行查看。

    1. import { NzTransferModule } from 'ng-zorro-antd/transfer';

    代码演示

    Transfer穿梭框 - 图1

    基本用法

    最基本的用法,展示了 nzDataSource 每行的渲染函数 nzRender 以及回调函数 nzChangenzSelectChange 的用法。

    1. import { Component, OnInit } from '@angular/core';
    2. @Component({
    3. selector: 'nz-demo-transfer-basic',
    4. template: `
    5. <nz-transfer
    6. [nzDataSource]="list"
    7. [nzDisabled]="disabled"
    8. [nzTitles]="['Source', 'Target']"
    9. (nzSelectChange)="select($event)"
    10. (nzChange)="change($event)"
    11. >
    12. </nz-transfer>
    13. <div style="margin-top: 8px;">
    14. <nz-switch [(ngModel)]="disabled" nzCheckedChildren="disabled" nzUnCheckedChildren="disabled"></nz-switch>
    15. <div></div>
    16. </div>
    17. `
    18. })
    19. export class NzDemoTransferBasicComponent implements OnInit {
    20. // tslint:disable-next-line:no-any
    21. list: any[] = [];
    22. disabled = false;
    23. ngOnInit(): void {
    24. for (let i = 0; i < 20; i++) {
    25. this.list.push({
    26. key: i.toString(),
    27. title: `content${i + 1}`,
    28. disabled: i % 3 < 1
    29. });
    30. }
    31. [2, 3].forEach(idx => (this.list[idx].direction = 'right'));
    32. }
    33. select(ret: {}): void {
    34. console.log('nzSelectChange', ret);
    35. }
    36. change(ret: {}): void {
    37. console.log('nzChange', ret);
    38. }
    39. }

    Transfer穿梭框 - 图2

    带搜索框

    带搜索框的穿梭框,可以自定义搜索函数。

    1. import { Component, OnInit } from '@angular/core';
    2. @Component({
    3. selector: 'nz-demo-transfer-search',
    4. template: `
    5. <nz-transfer
    6. [nzDataSource]="list"
    7. [nzDisabled]="disabled"
    8. nzShowSearch
    9. [nzFilterOption]="filterOption"
    10. (nzSearchChange)="search($event)"
    11. (nzSelectChange)="select($event)"
    12. (nzChange)="change($event)"
    13. >
    14. </nz-transfer>
    15. <div style="margin-top: 8px;">
    16. <nz-switch [(ngModel)]="disabled" nzCheckedChildren="disabled" nzUnCheckedChildren="disabled"></nz-switch>
    17. <div></div>
    18. </div>
    19. `
    20. })
    21. export class NzDemoTransferSearchComponent implements OnInit {
    22. // tslint:disable-next-line:no-any
    23. list: any[] = [];
    24. disabled = false;
    25. ngOnInit(): void {
    26. for (let i = 0; i < 20; i++) {
    27. this.list.push({
    28. key: i.toString(),
    29. title: `content${i + 1}`,
    30. description: `description of content${i + 1}`,
    31. direction: Math.random() * 2 > 1 ? 'right' : ''
    32. });
    33. }
    34. }
    35. // tslint:disable-next-line:no-any
    36. filterOption(inputValue: string, item: any): boolean {
    37. return item.description.indexOf(inputValue) > -1;
    38. }
    39. search(ret: {}): void {
    40. console.log('nzSearchChange', ret);
    41. }
    42. select(ret: {}): void {
    43. console.log('nzSelectChange', ret);
    44. }
    45. change(ret: {}): void {
    46. console.log('nzChange', ret);
    47. }
    48. }

    Transfer穿梭框 - 图3

    高级用法

    穿梭框高级用法,可配置操作文案,可定制宽高,可对底部进行自定义渲染。

    1. import { Component, OnInit } from '@angular/core';
    2. import { NzMessageService } from 'ng-zorro-antd/message';
    3. @Component({
    4. selector: 'nz-demo-transfer-advanced',
    5. template: `
    6. <nz-transfer
    7. [nzDataSource]="list"
    8. nzShowSearch
    9. [nzOperations]="['to right', 'to left']"
    10. [nzListStyle]="{ 'width.px': 250, 'height.px': 300 }"
    11. [nzRender]="render"
    12. [nzFooter]="footer"
    13. (nzSelectChange)="select($event)"
    14. (nzChange)="change($event)"
    15. >
    16. <ng-template #render let-item> {{ item.title }}-{{ item.description }} </ng-template>
    17. <ng-template #footer let-direction>
    18. <button nz-button (click)="reload(direction)" [nzSize]="'small'" style="float: right; margin: 5px;">
    19. reload
    20. </button>
    21. </ng-template>
    22. </nz-transfer>
    23. `
    24. })
    25. export class NzDemoTransferAdvancedComponent implements OnInit {
    26. list: Array<{ key: string; title: string; description: string; direction: string }> = [];
    27. ngOnInit(): void {
    28. this.getData();
    29. }
    30. getData(): void {
    31. const ret: Array<{ key: string; title: string; description: string; direction: string }> = [];
    32. for (let i = 0; i < 20; i++) {
    33. ret.push({
    34. key: i.toString(),
    35. title: `content${i + 1}`,
    36. description: `description of content${i + 1}`,
    37. direction: Math.random() * 2 > 1 ? 'right' : ''
    38. });
    39. }
    40. this.list = ret;
    41. }
    42. reload(direction: string): void {
    43. this.getData();
    44. this.msg.success(`your clicked ${direction}!`);
    45. }
    46. select(ret: {}): void {
    47. console.log('nzSelectChange', ret);
    48. }
    49. change(ret: {}): void {
    50. console.log('nzChange', ret);
    51. }
    52. constructor(public msg: NzMessageService) {}
    53. }

    Transfer穿梭框 - 图4

    自定义渲染行数据

    自定义渲染每一个 Transfer Item,可用于渲染复杂数据。

    1. import { Component, OnInit } from '@angular/core';
    2. import { NzMessageService } from 'ng-zorro-antd/message';
    3. @Component({
    4. selector: 'nz-demo-transfer-custom-item',
    5. template: `
    6. <nz-transfer
    7. [nzDataSource]="list"
    8. [nzListStyle]="{ 'width.px': 300, 'height.px': 300 }"
    9. [nzRender]="render"
    10. (nzSelectChange)="select($event)"
    11. (nzChange)="change($event)"
    12. >
    13. <ng-template #render let-item> <i nz-icon nzType="{{ item.icon }}"></i> {{ item.title }} </ng-template>
    14. </nz-transfer>
    15. `
    16. })
    17. export class NzDemoTransferCustomItemComponent implements OnInit {
    18. list: Array<{ key: string; title: string; description: string; direction: string; icon: string }> = [];
    19. ngOnInit(): void {
    20. this.getData();
    21. }
    22. getData(): void {
    23. const ret: Array<{ key: string; title: string; description: string; direction: string; icon: string }> = [];
    24. for (let i = 0; i < 20; i++) {
    25. ret.push({
    26. key: i.toString(),
    27. title: `content${i + 1}`,
    28. description: `description of content${i + 1}`,
    29. direction: Math.random() * 2 > 1 ? 'right' : '',
    30. icon: `frown-o`
    31. });
    32. }
    33. this.list = ret;
    34. }
    35. select(ret: {}): void {
    36. console.log('nzSelectChange', ret);
    37. }
    38. change(ret: {}): void {
    39. console.log('nzChange', ret);
    40. }
    41. constructor(public msg: NzMessageService) {}
    42. }

    Transfer穿梭框 - 图5

    二次校验

    利用 nzCanMove 允许在穿梭过程中二次校验;示例默认向右移时强制选中的第一项不可穿梭。

    1. import { Component, OnInit } from '@angular/core';
    2. import { TransferCanMove, TransferItem } from 'ng-zorro-antd/transfer';
    3. import { of, Observable } from 'rxjs';
    4. import { delay } from 'rxjs/operators';
    5. @Component({
    6. selector: 'nz-demo-transfer-can-move',
    7. template: `
    8. <nz-transfer
    9. [nzDataSource]="list"
    10. [nzCanMove]="canMove"
    11. (nzSelectChange)="select($event)"
    12. (nzChange)="change($event)"
    13. >
    14. </nz-transfer>
    15. `
    16. })
    17. export class NzDemoTransferCanMoveComponent implements OnInit {
    18. list: Array<{ key: string; title: string; disabled: boolean; direction?: string }> = [];
    19. ngOnInit(): void {
    20. for (let i = 0; i < 20; i++) {
    21. this.list.push({
    22. key: i.toString(),
    23. title: `content${i + 1}`,
    24. disabled: i % 3 < 1
    25. });
    26. }
    27. [2, 3].forEach(idx => (this.list[idx].direction = 'right'));
    28. }
    29. canMove(arg: TransferCanMove): Observable<TransferItem[]> {
    30. if (arg.direction === 'right' && arg.list.length > 0) {
    31. arg.list.splice(0, 1);
    32. }
    33. // or
    34. // if (arg.direction === 'right' && arg.list.length > 0) delete arg.list[0];
    35. return of(arg.list).pipe(delay(1000));
    36. }
    37. select(ret: {}): void {
    38. console.log('nzSelectChange', ret);
    39. }
    40. change(ret: {}): void {
    41. console.log('nzChange', ret);
    42. }
    43. }

    Transfer穿梭框 - 图6

    表格穿梭框

    使用 Table 组件作为自定义渲染列表。

    1. import { Component, OnInit } from '@angular/core';
    2. import { TransferItem } from 'ng-zorro-antd/transfer';
    3. @Component({
    4. selector: 'nz-demo-transfer-table-transfer',
    5. template: `
    6. <nz-transfer
    7. [nzDataSource]="list"
    8. [nzDisabled]="disabled"
    9. [nzShowSearch]="showSearch"
    10. [nzShowSelectAll]="false"
    11. [nzRenderList]="[renderList, renderList]"
    12. (nzSelectChange)="select($event)"
    13. (nzChange)="change($event)"
    14. >
    15. <ng-template
    16. #renderList
    17. let-items
    18. let-direction="direction"
    19. let-stat="stat"
    20. let-disabled="disabled"
    21. let-onItemSelectAll="onItemSelectAll"
    22. let-onItemSelect="onItemSelect"
    23. >
    24. <nz-table #t [nzData]="convertItems(items)" nzSize="small">
    25. <thead>
    26. <tr>
    27. <th
    28. nzShowCheckbox
    29. [nzDisabled]="disabled"
    30. [nzChecked]="stat.checkAll"
    31. [nzIndeterminate]="stat.checkHalf"
    32. (nzCheckedChange)="onItemSelectAll($event)"
    33. ></th>
    34. <th>Name</th>
    35. <th *ngIf="direction === 'left'">Tag</th>
    36. <th>Description</th>
    37. </tr>
    38. </thead>
    39. <tbody>
    40. <tr *ngFor="let data of t.data" (click)="onItemSelect(data)">
    41. <td
    42. nzShowCheckbox
    43. [nzChecked]="data.checked"
    44. [nzDisabled]="disabled || data.disabled"
    45. (nzCheckedChange)="onItemSelect(data)"
    46. ></td>
    47. <td>{{ data.title }}</td>
    48. <td *ngIf="direction === 'left'">
    49. <nz-tag>{{ data.tag }}</nz-tag>
    50. </td>
    51. <td>{{ data.description }}</td>
    52. </tr>
    53. </tbody>
    54. </nz-table>
    55. </ng-template>
    56. </nz-transfer>
    57. <div style="margin-top: 8px;">
    58. <nz-switch [(ngModel)]="disabled" nzCheckedChildren="disabled" nzUnCheckedChildren="disabled"></nz-switch>
    59. <nz-switch [(ngModel)]="showSearch" nzCheckedChildren="showSearch" nzUnCheckedChildren="showSearch"></nz-switch>
    60. </div>
    61. `
    62. })
    63. export class NzDemoTransferTableTransferComponent implements OnInit {
    64. // tslint:disable-next-line:no-any
    65. list: any[] = [];
    66. disabled = false;
    67. showSearch = false;
    68. ngOnInit(): void {
    69. for (let i = 0; i < 20; i++) {
    70. this.list.push({
    71. key: i.toString(),
    72. title: `content${i + 1}`,
    73. description: `description of content${i + 1}`,
    74. disabled: i % 4 === 0,
    75. tag: ['cat', 'dog', 'bird'][i % 3]
    76. });
    77. }
    78. [2, 3].forEach(idx => (this.list[idx].direction = 'right'));
    79. }
    80. convertItems(items: TransferItem[]): TransferItem[] {
    81. return items.filter(i => !i.hide);
    82. }
    83. select(ret: {}): void {
    84. console.log('nzSelectChange', ret);
    85. }
    86. change(ret: {}): void {
    87. console.log('nzChange', ret);
    88. }
    89. }

    Transfer穿梭框 - 图7

    树穿梭框

    使用 Tree 组件作为自定义渲染列表。

    1. // tslint:disable: no-any
    2. import { ChangeDetectionStrategy, Component, ViewChild } from '@angular/core';
    3. import { NzTreeNode } from 'ng-zorro-antd/core';
    4. import { TransferChange, TransferItem } from 'ng-zorro-antd/transfer';
    5. import { NzTreeComponent } from 'ng-zorro-antd/tree';
    6. @Component({
    7. selector: 'nz-demo-transfer-tree-transfer',
    8. template: `
    9. <nz-transfer
    10. [nzDataSource]="list"
    11. [nzShowSelectAll]="false"
    12. [nzRenderList]="[leftRenderList, null]"
    13. (nzChange)="change($event)"
    14. >
    15. <ng-template #leftRenderList let-items let-onItemSelectAll="onItemSelectAll" let-onItemSelect="onItemSelect">
    16. <nz-tree #tree [nzData]="treeData" nzExpandAll nzBlockNode>
    17. <ng-template #nzTreeTemplate let-node>
    18. <span
    19. class="ant-tree-checkbox"
    20. [class.ant-tree-checkbox-disabled]="node.isDisabled"
    21. [class.ant-tree-checkbox-checked]="node.isChecked"
    22. (click)="checkBoxChange(node, onItemSelect)"
    23. >
    24. <span class="ant-tree-checkbox-inner"></span>
    25. </span>
    26. <span
    27. (click)="checkBoxChange(node, onItemSelect)"
    28. class="ant-tree-node-content-wrapper ant-tree-node-content-wrapper-open"
    29. >{{ node.title }}</span
    30. >
    31. </ng-template>
    32. </nz-tree>
    33. </ng-template>
    34. </nz-transfer>
    35. `,
    36. changeDetection: ChangeDetectionStrategy.OnPush
    37. })
    38. export class NzDemoTransferTreeTransferComponent {
    39. @ViewChild('tree', { static: true }) tree: NzTreeComponent;
    40. list: any[] = [
    41. { id: 1, parentid: 0, title: 'parent 1' },
    42. { id: 2, parentid: 1, title: 'leaf 1-1', disabled: true, isLeaf: true },
    43. { id: 3, parentid: 1, title: 'leaf 1-2', isLeaf: true }
    44. ];
    45. treeData = this.generateTree(this.list);
    46. checkedNodeList: NzTreeNode[] = [];
    47. private generateTree(arr: TransferItem[]): TransferItem[] {
    48. const tree: TransferItem[] = [];
    49. const mappedArr: any = {};
    50. let arrElem: TransferItem;
    51. let mappedElem: TransferItem;
    52. for (let i = 0, len = arr.length; i < len; i++) {
    53. arrElem = arr[i];
    54. mappedArr[arrElem.id] = { ...arrElem };
    55. mappedArr[arrElem.id].children = [];
    56. }
    57. for (const id in mappedArr) {
    58. if (mappedArr.hasOwnProperty(id)) {
    59. mappedElem = mappedArr[id];
    60. if (mappedElem.parentid) {
    61. mappedArr[mappedElem.parentid].children.push(mappedElem);
    62. } else {
    63. tree.push(mappedElem);
    64. }
    65. }
    66. }
    67. return tree;
    68. }
    69. checkBoxChange(node: NzTreeNode, onItemSelect: (item: TransferItem) => void): void {
    70. if (node.isDisabled) {
    71. return;
    72. }
    73. node.isChecked = !node.isChecked;
    74. if (node.isChecked) {
    75. this.checkedNodeList.push(node);
    76. } else {
    77. const idx = this.checkedNodeList.indexOf(node);
    78. if (idx !== -1) {
    79. this.checkedNodeList.splice(idx, 1);
    80. }
    81. }
    82. const item = this.list.find(w => w.id === node.origin.id);
    83. onItemSelect(item);
    84. }
    85. change(ret: TransferChange): void {
    86. const isDisabled = ret.to === 'right';
    87. this.checkedNodeList.forEach(node => {
    88. node.isDisabled = isDisabled;
    89. node.isChecked = isDisabled;
    90. });
    91. }
    92. }

    API

    nz-transfercomponent

    参数说明类型默认值
    [nzDataSource]数据源,其中若数据属性 direction: 'right' 将会被渲染到右边一栏中或使用 nzTargetKeysTransferItem[][]
    [nzDisabled]是否禁用booleanfalse
    [nzTitles]标题集合,顺序从左至右string[]['', '']
    [nzOperations]操作文案集合,顺序从下至上string[]['', '']
    [nzListStyle]两个穿梭框的自定义样式,等同 ngStyleobject-
    [nzItemUnit]单数单位string'项目'
    [nzItemsUnit]复数单位string'项目'
    [nzRenderList]自定义渲染列表,见示例Array<TemplateRef<void> | null>[null, null]
    [nzRender]每行数据渲染模板,见示例TemplateRef<void>-
    [nzFooter]底部渲染模板,见示例TemplateRef<void>-
    [nzShowSearch]是否显示搜索框booleanfalse
    [nzFilterOption]接收 inputValueoption 两个参数,当 option 符合筛选条件时,应返回 true,反之则返回 false(inputValue: string, item: TransferItem) => boolean-
    [nzSearchPlaceholder]搜索框的默认值string'请输入搜索内容'
    [nzNotFoundContent]当列表为空时显示的内容string'列表为空'
    [nzCanMove]穿梭时二次校验。注意: 穿梭组件内部始终只保留一份数据,二次校验过程中需取消穿梭项则直接删除该项;具体用法见示例。(arg: TransferCanMove) => Observable<TransferItem[]>-
    [nzTargetKeys]显示在右侧框数据的 key 集合string[]-
    (nzChange)选项在两栏之间转移时的回调函数EventEmitter<TransferChange>-
    (nzSearchChange)搜索框内容时改变时的回调函数EventEmitter<TransferSearchChange>-
    (nzSelectChange)选中项发生改变时的回调函数EventEmitter<TransferSearchChange>-

    TransferItem

    参数说明类型默认值
    title标题,用于显示及搜索关键字判断string-
    direction指定数据方向,若指定 right 为右栏,其他情况为左栏'left' | 'right'-
    disabled指定checkbox为不可用状态booleanfalse
    checked指定checkbox为选中状态booleanfalse

    TransferCanMove

    参数说明类型默认值
    direction数据方向'left' | 'right'-
    list数据源TransferItem[][]

    TransferChange

    参数说明类型默认值
    from数据方向'left' | 'right'-
    to数据方向'left' | 'right'-
    list数据源TransferItem[][]

    TransferSearchChange

    参数说明类型默认值
    direction数据方向'left' | 'right'-
    value搜索关键词string-

    nzRenderList

    参数说明类型默认值
    direction渲染列表的方向'left' | 'right'-
    disabled是否禁用列表boolean-
    items过滤后的数据TransferItem[]-
    onItemSelect勾选条目(item: TransferItem) => void-
    onItemSelectAll勾选一组条目(selected: boolean) => void-