Table表格

展示行列数据。

何时使用#

  • 当有大量结构化的数据需要展现时;
  • 当需要对数据进行排序、搜索、分页、自定义操作等复杂行为时。

单独引入此组件#

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

import { NzTableModule } from 'ng-zorro-antd/table';

如何使用#

Table 组件同时具备了易用性和高度可定制性

高度定制#

nz-table 组件中完整的暴露了 W3C标准 <table> 的所有组成部分,你可以像使用 table 元素一样使用 nz-table ,根据依据业务需求,使用者可以自由的控制任何一个部分的样式、内容、逻辑和事件绑定。

组件增强#

nz-table, thead, th, td 等多个暴露的元素上,组件提供了增强语法,经过配置之后可以很方便的实现多选、过滤、排序、固定列、固定表头、服务端分页等功能。

数据处理#

传入[nzData]中的数据,经过处理之后,可以通过 模板变量 获取当前展示表格部分的数据,再使用 *ngFor 依据需求将数据渲染。

<nz-table #basicTable [nzData]="dataSet">
  <thead>
    <tr>
      <th>Name</th>
      <th>Age</th>
      <th>Address</th>
      <th>Action</th>
    </tr>
  </thead>
  <tbody>
    <tr *ngFor="let data of basicTable.data">
      <td>{{data.name}}</td>
      <td>{{data.age}}</td>
      <td>{{data.address}}</td>
      <td>
        <a>Action 一 {{data.name}}</a>
        <nz-divider nzType="vertical"></nz-divider>
        <a>Delete</a>
      </td>
    </tr>
  </tbody>
</nz-table>

代码演示

Name
Age
Address
Action
John Brown32New York No. 1 Lake ParkAction 一 John BrownDelete
Jim Green42London No. 1 Lake ParkAction 一 Jim GreenDelete
Joe Black32Sidney No. 1 Lake ParkAction 一 Joe BlackDelete

简单的表格,最后一列是各种操作。

expand codeexpand code
import { Component } from '@angular/core';

@Component({
  selector: 'nz-demo-table-basic',
  template: `
    <nz-table #basicTable [nzData]="listOfData">
      <thead>
        <tr>
          <th>Name</th>
          <th>Age</th>
          <th>Address</th>
          <th>Action</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of basicTable.data">
          <td>{{ data.name }}</td>
          <td>{{ data.age }}</td>
          <td>{{ data.address }}</td>
          <td>
            <a>Action 一 {{ data.name }}</a>
            <nz-divider nzType="vertical"></nz-divider>
            <a>Delete</a>
          </td>
        </tr>
      </tbody>
    </nz-table>
  `
})
export class NzDemoTableBasicComponent {
  listOfData = [
    {
      key: '1',
      name: 'John Brown',
      age: 32,
      address: 'New York No. 1 Lake Park'
    },
    {
      key: '2',
      name: 'Jim Green',
      age: 42,
      address: 'London No. 1 Lake Park'
    },
    {
      key: '3',
      name: 'Joe Black',
      age: 32,
      address: 'Sidney No. 1 Lake Park'
    }
  ];
}
Name
Age
Address
Edward King 032London, Park Lane no. 0
Edward King 132London, Park Lane no. 1
Edward King 232London, Park Lane no. 2
Edward King 332London, Park Lane no. 3
Edward King 432London, Park Lane no. 4
Edward King 532London, Park Lane no. 5
Edward King 632London, Park Lane no. 6
Edward King 732London, Park Lane no. 7
Edward King 832London, Park Lane no. 8
Edward King 932London, Park Lane no. 9

第一列是联动的选择框,增加 nzShowCheckbox 后,th 获得和 nz-checkbox 一样的功能,选择后进行操作,完成后清空选择,请注意:数据逻辑需要自行控制。

expand codeexpand code
import { Component, OnInit } from '@angular/core';

export interface Data {
  id: number;
  name: string;
  age: number;
  address: string;
  disabled: boolean;
}

@Component({
  selector: 'nz-demo-table-row-selection-and-operation',
  template: `
    <div class="operate">
      <button
        nz-button
        [disabled]="numberOfChecked === 0"
        [nzType]="'primary'"
        [nzLoading]="isOperating"
        (click)="operateData()"
      >
        Reload
      </button>
      <span *ngIf="numberOfChecked">Selected {{ numberOfChecked }} items</span>
    </div>
    <nz-table
      #rowSelectionTable
      nzShowPagination
      nzShowSizeChanger
      [nzData]="listOfAllData"
      (nzCurrentPageDataChange)="currentPageDataChange($event)"
    >
      <thead>
        <tr>
          <th
            nzShowCheckbox
            [(nzChecked)]="isAllDisplayDataChecked"
            [nzIndeterminate]="isIndeterminate"
            (nzCheckedChange)="checkAll($event)"
          ></th>
          <th>Name</th>
          <th>Age</th>
          <th>Address</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of rowSelectionTable.data">
          <td
            nzShowCheckbox
            [(nzChecked)]="mapOfCheckedId[data.id]"
            [nzDisabled]="data.disabled"
            (nzCheckedChange)="refreshStatus()"
          ></td>
          <td>{{ data.name }}</td>
          <td>{{ data.age }}</td>
          <td>{{ data.address }}</td>
        </tr>
      </tbody>
    </nz-table>
  `,
  styles: [
    `
      .operate {
        margin-bottom: 16px;
      }

      .operate span {
        margin-left: 8px;
      }
    `
  ]
})
export class NzDemoTableRowSelectionAndOperationComponent implements OnInit {
  isAllDisplayDataChecked = false;
  isOperating = false;
  isIndeterminate = false;
  listOfDisplayData: Data[] = [];
  listOfAllData: Data[] = [];
  mapOfCheckedId: { [key: string]: boolean } = {};
  numberOfChecked = 0;

  currentPageDataChange($event: Data[]): void {
    this.listOfDisplayData = $event;
    this.refreshStatus();
  }

  refreshStatus(): void {
    this.isAllDisplayDataChecked = this.listOfDisplayData
      .filter(item => !item.disabled)
      .every(item => this.mapOfCheckedId[item.id]);
    this.isIndeterminate =
      this.listOfDisplayData.filter(item => !item.disabled).some(item => this.mapOfCheckedId[item.id]) &&
      !this.isAllDisplayDataChecked;
    this.numberOfChecked = this.listOfAllData.filter(item => this.mapOfCheckedId[item.id]).length;
  }

  checkAll(value: boolean): void {
    this.listOfDisplayData.filter(item => !item.disabled).forEach(item => (this.mapOfCheckedId[item.id] = value));
    this.refreshStatus();
  }

  operateData(): void {
    this.isOperating = true;
    setTimeout(() => {
      this.listOfAllData.forEach(item => (this.mapOfCheckedId[item.id] = false));
      this.refreshStatus();
      this.isOperating = false;
    }, 1000);
  }

  ngOnInit(): void {
    for (let i = 0; i < 100; i++) {
      this.listOfAllData.push({
        id: i,
        name: `Edward King ${i}`,
        age: 32,
        address: `London, Park Lane no. ${i}`,
        disabled: i % 2 === 0
      });
    }
  }
}
Name
Age
Address
Edward King 032London, Park Lane no. 0
Edward King 132London, Park Lane no. 1
Edward King 232London, Park Lane no. 2
Edward King 332London, Park Lane no. 3
Edward King 432London, Park Lane no. 4
Edward King 532London, Park Lane no. 5
Edward King 632London, Park Lane no. 6
Edward King 732London, Park Lane no. 7
Edward King 832London, Park Lane no. 8
Edward King 932London, Park Lane no. 9

通过 nzShowRowSelectionnzSelections 自定义选择项.

expand codeexpand code
import { Component, OnInit } from '@angular/core';

interface ItemData {
  id: number;
  name: string;
  age: number;
  address: string;
}

@Component({
  selector: 'nz-demo-table-row-selection-custom',
  template: `
    <nz-table
      #rowSelectionTable
      nzShowSizeChanger
      [nzData]="listOfAllData"
      (nzCurrentPageDataChange)="currentPageDataChange($event)"
    >
      <thead>
        <tr>
          <th
            nzShowCheckbox
            nzShowRowSelection
            [nzSelections]="listOfSelection"
            [(nzChecked)]="isAllDisplayDataChecked"
            [nzIndeterminate]="isIndeterminate"
            (nzCheckedChange)="checkAll($event)"
          ></th>
          <th>Name</th>
          <th>Age</th>
          <th>Address</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of rowSelectionTable.data">
          <td nzShowCheckbox [(nzChecked)]="mapOfCheckedId[data.id]" (nzCheckedChange)="refreshStatus()"></td>
          <td>{{ data.name }}</td>
          <td>{{ data.age }}</td>
          <td>{{ data.address }}</td>
        </tr>
      </tbody>
    </nz-table>
  `
})
export class NzDemoTableRowSelectionCustomComponent implements OnInit {
  listOfSelection = [
    {
      text: 'Select All Row',
      onSelect: () => {
        this.checkAll(true);
      }
    },
    {
      text: 'Select Odd Row',
      onSelect: () => {
        this.listOfDisplayData.forEach((data, index) => (this.mapOfCheckedId[data.id] = index % 2 !== 0));
        this.refreshStatus();
      }
    },
    {
      text: 'Select Even Row',
      onSelect: () => {
        this.listOfDisplayData.forEach((data, index) => (this.mapOfCheckedId[data.id] = index % 2 === 0));
        this.refreshStatus();
      }
    }
  ];
  isAllDisplayDataChecked = false;
  isIndeterminate = false;
  listOfDisplayData: ItemData[] = [];
  listOfAllData: ItemData[] = [];
  mapOfCheckedId: { [key: string]: boolean } = {};

  currentPageDataChange($event: ItemData[]): void {
    this.listOfDisplayData = $event;
    this.refreshStatus();
  }

  refreshStatus(): void {
    this.isAllDisplayDataChecked = this.listOfDisplayData.every(item => this.mapOfCheckedId[item.id]);
    this.isIndeterminate =
      this.listOfDisplayData.some(item => this.mapOfCheckedId[item.id]) && !this.isAllDisplayDataChecked;
  }

  checkAll(value: boolean): void {
    this.listOfDisplayData.forEach(item => (this.mapOfCheckedId[item.id] = value));
    this.refreshStatus();
  }

  ngOnInit(): void {
    for (let i = 0; i < 100; i++) {
      this.listOfAllData.push({
        id: i,
        name: `Edward King ${i}`,
        age: 32,
        address: `London, Park Lane no. ${i}`
      });
    }
  }
}
Name
Age
Address
John Brown32New York No. 1 Lake Park
Jim Green42London No. 1 Lake Park
Joe Black32Sidney No. 1 Lake Park
Jim Red32London No. 2 Lake Park

对某一列数据进行筛选,通过指定 thnzShowFilter 属性来展示筛选菜单, 使用 nzFilters 属性来指定筛选选项,nzFilterChange 用于获取当前选中的选项,nzFilterMultiple 用于指定多选和单选。

对某一列数据进行排序,通过指定 thnzShowSort 属性来展示排序按钮,使用 nzSortKey 来指定排序的 key,在 thead 上通过 nzSortChange 来获取排序改变事件,通过 nzSingleSort 来指定是否单列排序。

expand codeexpand code
import { Component } from '@angular/core';

@Component({
  selector: 'nz-demo-table-head',
  template: `
    <nz-table #filterTable [nzData]="listOfDisplayData">
      <thead (nzSortChange)="sort($event)" nzSingleSort>
        <tr>
          <th
            nzShowSort
            nzSortKey="name"
            nzShowFilter
            [nzFilters]="listOfName"
            (nzFilterChange)="filter($event, searchAddress)"
          >
            Name
          </th>
          <th nzShowSort nzSortKey="age">Age</th>
          <th
            nzShowSort
            nzSortKey="address"
            nzShowFilter
            [nzFilterMultiple]="false"
            [nzFilters]="listOfAddress"
            (nzFilterChange)="filter(listOfSearchName, $event)"
          >
            Address
          </th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of filterTable.data">
          <td>{{ data.name }}</td>
          <td>{{ data.age }}</td>
          <td>{{ data.address }}</td>
        </tr>
      </tbody>
    </nz-table>
  `
})
export class NzDemoTableHeadComponent {
  sortName: string | null = null;
  sortValue: string | null = null;
  searchAddress: string;
  listOfName = [{ text: 'Joe', value: 'Joe' }, { text: 'Jim', value: 'Jim' }];
  listOfAddress = [{ text: 'London', value: 'London' }, { text: 'Sidney', value: 'Sidney' }];
  listOfSearchName: string[] = [];
  listOfData: Array<{ name: string; age: number; address: string; [key: string]: string | number }> = [
    {
      name: 'John Brown',
      age: 32,
      address: 'New York No. 1 Lake Park'
    },
    {
      name: 'Jim Green',
      age: 42,
      address: 'London No. 1 Lake Park'
    },
    {
      name: 'Joe Black',
      age: 32,
      address: 'Sidney No. 1 Lake Park'
    },
    {
      name: 'Jim Red',
      age: 32,
      address: 'London No. 2 Lake Park'
    }
  ];
  listOfDisplayData: Array<{ name: string; age: number; address: string; [key: string]: string | number }> = [
    ...this.listOfData
  ];

  sort(sort: { key: string; value: string }): void {
    this.sortName = sort.key;
    this.sortValue = sort.value;
    this.search();
  }

  filter(listOfSearchName: string[], searchAddress: string): void {
    this.listOfSearchName = listOfSearchName;
    this.searchAddress = searchAddress;
    this.search();
  }

  search(): void {
    /** filter data **/
    const filterFunc = (item: { name: string; age: number; address: string }) =>
      (this.searchAddress ? item.address.indexOf(this.searchAddress) !== -1 : true) &&
      (this.listOfSearchName.length ? this.listOfSearchName.some(name => item.name.indexOf(name) !== -1) : true);
    const data = this.listOfData.filter(item => filterFunc(item));
    /** sort data **/
    if (this.sortName && this.sortValue) {
      this.listOfDisplayData = data.sort((a, b) =>
        this.sortValue === 'ascend'
          ? a[this.sortName!] > b[this.sortName!]
            ? 1
            : -1
          : b[this.sortName!] > a[this.sortName!]
          ? 1
          : -1
      );
    } else {
      this.listOfDisplayData = data;
    }
  }
}
Name
Age
Address
empty

暂无数据

通过设置 filter 对象的 { byDefault: true } 属性来默认启用一个筛选器。注意,你必须同时自行设置过滤后应当展示的列表项,为了保持数据流的清晰和数据的一致性,组件库不会为你做这项工作。详情请见 demo。

expand codeexpand code
import { Component } from '@angular/core';

@Component({
  selector: 'nz-demo-table-default-filter',
  template: `
    <nz-table #filterTable [nzData]="listOfDisplayData">
      <thead (nzSortChange)="sort($event)" nzSingleSort>
        <tr>
          <th
            nzShowSort
            nzSortKey="name"
            nzShowFilter
            [nzFilters]="listOfName"
            (nzFilterChange)="filter($event, searchAddress)"
          >
            Name
          </th>
          <th nzShowSort nzSortKey="age">Age</th>
          <th
            nzShowSort
            nzSortKey="address"
            nzShowFilter
            [nzFilterMultiple]="false"
            [nzFilters]="listOfAddress"
            (nzFilterChange)="filter(listOfSearchName, $event)"
          >
            Address
          </th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of filterTable.data">
          <td>{{ data.name }}</td>
          <td>{{ data.age }}</td>
          <td>{{ data.address }}</td>
        </tr>
      </tbody>
    </nz-table>
  `
})
export class NzDemoTableDefaultFilterComponent {
  listOfName = [{ text: 'Joe', value: 'Joe', byDefault: true }, { text: 'Jim', value: 'Jim' }];
  listOfAddress = [{ text: 'London', value: 'London', byDefault: true }, { text: 'Sidney', value: 'Sidney' }];
  listOfSearchName = ['Joe']; // You need to change it as well!
  sortName: string | null = null;
  sortValue: string | null = null;
  searchAddress = 'London';
  listOfData: Array<{ name: string; age: number; address: string; [key: string]: string | number }> = [
    {
      name: 'John Brown',
      age: 32,
      address: 'New York No. 1 Lake Park'
    },
    {
      name: 'Jim Green',
      age: 42,
      address: 'London No. 1 Lake Park'
    },
    {
      name: 'Joe Black',
      age: 32,
      address: 'Sidney No. 1 Lake Park'
    },
    {
      name: 'Jim Red',
      age: 32,
      address: 'London No. 2 Lake Park'
    }
  ];
  // You need to change it as well!
  listOfDisplayData: Array<{ name: string; age: number; address: string; [key: string]: string | number }> = [];

  sort(sort: { key: string; value: string }): void {
    this.sortName = sort.key;
    this.sortValue = sort.value;
    this.search();
  }

  filter(listOfSearchName: string[], searchAddress: string): void {
    console.log(listOfSearchName, searchAddress);
    this.listOfSearchName = listOfSearchName;
    this.searchAddress = searchAddress;
    this.search();
  }

  search(): void {
    /** filter data **/
    const filterFunc = (item: { name: string; age: number; address: string }) =>
      (this.searchAddress ? item.address.indexOf(this.searchAddress) !== -1 : true) &&
      (this.listOfSearchName.length ? this.listOfSearchName.some(name => item.name.indexOf(name) !== -1) : true);
    const data = this.listOfData.filter(item => filterFunc(item));
    /** sort data **/
    if (this.sortName && this.sortValue) {
      this.listOfDisplayData = data.sort((a, b) =>
        this.sortValue === 'ascend'
          ? a[this.sortName!] > b[this.sortName!]
            ? 1
            : -1
          : b[this.sortName!] > a[this.sortName!]
          ? 1
          : -1
      );
    } else {
      this.listOfDisplayData = data;
    }
  }
}
Name
Age
Address
John Brown32New York No. 1 Lake Park
Jim Green42London No. 1 Lake Park
Joe Black32Sidney No. 1 Lake Park
Jim Red32London No. 2 Lake Park

使用受控属性对筛选状态进行控制。

  1. th 中定义了 nzSort 属性即视为受控模式。
  2. 通过手动指定 nzSort 来指定当前列的排序状态
  3. 通过 thnzSortChange 事件来获取当前列排序状态的改变
  4. 不可与 thead 中的 nzSortChangenzSingleSort 同时使用
expand codeexpand code
import { Component } from '@angular/core';

interface Data {
  name: string;
  age: number;
  address: string;

  // tslint:disable-next-line:no-any
  [key: string]: any;
}

@Component({
  selector: 'nz-demo-table-reset-filter',
  template: `
    <div class="table-operations">
      <button nz-button (click)="sort('age', 'descend')">Sort age</button>
      <button nz-button (click)="resetFilters()">Clear filters</button>
      <button nz-button (click)="resetSortAndFilters()">Clear filters and sorters</button>
    </div>
    <nz-table #filterTable [nzData]="listOfDisplayData">
      <thead>
        <tr>
          <th
            nzShowSort
            nzShowFilter
            [(nzSort)]="mapOfSort.name"
            (nzSortChange)="sort('name', $event)"
            [nzFilters]="listOfFilterName"
            (nzFilterChange)="search($event, listOfSearchAddress)"
          >
            Name
          </th>
          <th nzShowSort [(nzSort)]="mapOfSort.age" (nzSortChange)="sort('age', $event)">Age</th>
          <th
            nzShowSort
            nzShowFilter
            [(nzSort)]="mapOfSort.address"
            (nzSortChange)="sort('address', $event)"
            [nzFilters]="listOfFilterAddress"
            (nzFilterChange)="search(listOfSearchName, $event)"
          >
            Address
          </th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of filterTable.data">
          <td>{{ data.name }}</td>
          <td>{{ data.age }}</td>
          <td>{{ data.address }}</td>
        </tr>
      </tbody>
    </nz-table>
  `,
  styles: [
    `
      .table-operations {
        margin-bottom: 16px;
      }

      .table-operations > button {
        margin-right: 8px;
      }
    `
  ]
})
export class NzDemoTableResetFilterComponent {
  listOfSearchName: string[] = [];
  listOfSearchAddress: string[] = [];
  listOfFilterName = [{ text: 'Joe', value: 'Joe' }, { text: 'Jim', value: 'Jim' }];
  listOfFilterAddress = [{ text: 'London', value: 'London' }, { text: 'Sidney', value: 'Sidney' }];
  listOfData: Data[] = [
    {
      name: 'John Brown',
      age: 32,
      address: 'New York No. 1 Lake Park'
    },
    {
      name: 'Jim Green',
      age: 42,
      address: 'London No. 1 Lake Park'
    },
    {
      name: 'Joe Black',
      age: 32,
      address: 'Sidney No. 1 Lake Park'
    },
    {
      name: 'Jim Red',
      age: 32,
      address: 'London No. 2 Lake Park'
    }
  ];
  listOfDisplayData = [...this.listOfData];
  mapOfSort: { [key: string]: string | null } = {
    name: null,
    age: null,
    address: null
  };
  sortName: string | null = null;
  sortValue: string | null = null;

  sort(sortName: string, value: string): void {
    this.sortName = sortName;
    this.sortValue = value;
    for (const key in this.mapOfSort) {
      this.mapOfSort[key] = key === sortName ? value : null;
    }
    this.search(this.listOfSearchName, this.listOfSearchAddress);
  }

  search(listOfSearchName: string[], listOfSearchAddress: string[]): void {
    this.listOfSearchName = listOfSearchName;
    this.listOfSearchAddress = listOfSearchAddress;
    const filterFunc = (item: Data) =>
      (this.listOfSearchAddress.length
        ? this.listOfSearchAddress.some(address => item.address.indexOf(address) !== -1)
        : true) &&
      (this.listOfSearchName.length ? this.listOfSearchName.some(name => item.name.indexOf(name) !== -1) : true);
    const listOfData = this.listOfData.filter((item: Data) => filterFunc(item));
    if (this.sortName && this.sortValue) {
      this.listOfDisplayData = listOfData.sort((a, b) =>
        this.sortValue === 'ascend'
          ? a[this.sortName!] > b[this.sortName!]
            ? 1
            : -1
          : b[this.sortName!] > a[this.sortName!]
          ? 1
          : -1
      );
    } else {
      this.listOfDisplayData = listOfData;
    }
  }

  resetFilters(): void {
    this.listOfFilterName = [{ text: 'Joe', value: 'Joe' }, { text: 'Jim', value: 'Jim' }];
    this.listOfFilterAddress = [{ text: 'London', value: 'London' }, { text: 'Sidney', value: 'Sidney' }];
    this.listOfSearchName = [];
    this.listOfSearchAddress = [];
    this.search(this.listOfSearchName, this.listOfSearchAddress);
  }

  resetSortAndFilters(): void {
    this.sortName = null;
    this.sortValue = null;
    this.mapOfSort = {
      name: null,
      age: null,
      address: null
    };
    this.resetFilters();
    this.search(this.listOfSearchName, this.listOfSearchAddress);
  }
}
Name
Age
Address
John Brown32New York No. 1 Lake Park
Jim Green42London No. 1 Lake Park
Joe Black32Sidney No. 1 Lake Park
Jim Red32London No. 2 Lake Park

通过 nz-dropdownnzFiltersnzFilterChange 定义自定义的列筛选功能,并实现一个搜索列的示例,实际使用中建议将搜索组件进行单独封装。

expand codeexpand code
import { Component } from '@angular/core';

@Component({
  selector: 'nz-demo-table-custom-filter-panel',
  template: `
    <nz-table #nzTable [nzData]="listOfDisplayData">
      <thead>
        <tr>
          <th nzCustomFilter>
            Name
            <i
              nz-th-extra
              class="ant-table-filter-icon"
              nz-icon
              nz-dropdown
              #dropdown="nzDropdown"
              nzType="search"
              [nzDropdownMenu]="menu"
              [class.ant-table-filter-open]="dropdown.nzVisible"
              nzTrigger="click"
              nzPlacement="bottomRight"
              [nzClickHide]="false"
              nzTableFilter
            ></i>
          </th>
          <th>Age</th>
          <th nzShowFilter [nzFilters]="listOfFilterAddress" (nzFilterChange)="filterAddressChange($event)">Address</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of nzTable.data">
          <td>{{ data.name }}</td>
          <td>{{ data.age }}</td>
          <td>{{ data.address }}</td>
        </tr>
      </tbody>
    </nz-table>
    <nz-dropdown-menu #menu="nzDropdownMenu">
      <div class="search-box">
        <input type="text" nz-input placeholder="Search name" [(ngModel)]="searchValue" />
        <button nz-button nzSize="small" nzType="primary" (click)="search()" class="search-button">
          Search
        </button>
        <button nz-button nzSize="small" (click)="reset()">Reset</button>
      </div>
    </nz-dropdown-menu>
  `,
  styles: [
    `
      .search-box {
        padding: 8px;
      }

      .search-box input {
        width: 188px;
        margin-bottom: 8px;
        display: block;
      }

      .search-box button {
        width: 90px;
      }

      .search-button {
        margin-right: 8px;
      }
    `
  ]
})
export class NzDemoTableCustomFilterPanelComponent {
  searchValue = '';
  sortName: string | null = null;
  sortValue: string | null = null;
  listOfFilterAddress = [{ text: 'London', value: 'London' }, { text: 'Sidney', value: 'Sidney' }];
  listOfSearchAddress: string[] = [];
  listOfData: Array<{ name: string; age: number; address: string; [key: string]: string | number }> = [
    {
      name: 'John Brown',
      age: 32,
      address: 'New York No. 1 Lake Park'
    },
    {
      name: 'Jim Green',
      age: 42,
      address: 'London No. 1 Lake Park'
    },
    {
      name: 'Joe Black',
      age: 32,
      address: 'Sidney No. 1 Lake Park'
    },
    {
      name: 'Jim Red',
      age: 32,
      address: 'London No. 2 Lake Park'
    }
  ];
  listOfDisplayData = [...this.listOfData];

  reset(): void {
    this.searchValue = '';
    this.search();
  }

  sort(sortName: string, value: string): void {
    this.sortName = sortName;
    this.sortValue = value;
    this.search();
  }

  filterAddressChange(value: string[]): void {
    this.listOfSearchAddress = value;
    this.search();
  }

  search(): void {
    const filterFunc = (item: { name: string; age: number; address: string }) => {
      return (
        (this.listOfSearchAddress.length
          ? this.listOfSearchAddress.some(address => item.address.indexOf(address) !== -1)
          : true) && item.name.indexOf(this.searchValue) !== -1
      );
    };
    const data = this.listOfData.filter((item: { name: string; age: number; address: string }) => filterFunc(item));
    this.listOfDisplayData = data.sort((a, b) =>
      this.sortValue === 'ascend'
        ? a[this.sortName!] > b[this.sortName!]
          ? 1
          : -1
        : b[this.sortName!] > a[this.sortName!]
        ? 1
        : -1
    );
  }
}
Name
Gender
Email

这个例子通过简单的 ajax 读取方式,演示了如何从服务端读取并展现数据,具有筛选、排序等功能以及页面 loading 效果。开发者可以自行接入其他数据处理方式。

注意,此示例使用 模拟接口,展示数据可能不准确,请打开网络面板查看请求。

expand codeexpand code
import { HttpClient, HttpParams } from '@angular/common/http';
import { Component, Injectable, OnInit } from '@angular/core';
import { Observable } from 'rxjs';

interface ItemData {
  gender: string;
  name: Name;
  email: string;
}

interface Name {
  title: string;
  first: string;
  last: string;
}

@Injectable()
export class RandomUserService {
  randomUserUrl = 'https://api.randomuser.me/';

  getUsers(
    pageIndex: number = 1,
    pageSize: number = 10,
    sortField: string,
    sortOrder: string,
    genders: string[]
  ): Observable<{ results: ItemData[] }> {
    let params = new HttpParams()
      .append('page', `${pageIndex}`)
      .append('results', `${pageSize}`)
      .append('sortField', sortField)
      .append('sortOrder', sortOrder);
    genders.forEach(gender => {
      params = params.append('gender', gender);
    });
    return this.http.get<{ results: ItemData[] }>(`${this.randomUserUrl}`, {
      params
    });
  }

  constructor(private http: HttpClient) {}
}

@Component({
  selector: 'nz-demo-table-ajax',
  providers: [RandomUserService],
  template: `
    <nz-table
      #ajaxTable
      nzShowSizeChanger
      [nzFrontPagination]="false"
      [nzData]="listOfData"
      [nzLoading]="loading"
      [nzTotal]="total"
      [(nzPageIndex)]="pageIndex"
      [(nzPageSize)]="pageSize"
      (nzPageIndexChange)="searchData()"
      (nzPageSizeChange)="searchData(true)"
    >
      <thead (nzSortChange)="sort($event)" nzSingleSort>
        <tr>
          <th nzShowSort nzSortKey="name">Name</th>
          <th nzShowFilter [nzFilters]="filterGender" (nzFilterChange)="updateFilter($event)">Gender</th>
          <th nzShowSort nzSortKey="email"><span>Email</span></th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of ajaxTable.data">
          <td>{{ data.name.first }} {{ data.name.last }}</td>
          <td>{{ data.gender }}</td>
          <td>{{ data.email }}</td>
        </tr>
      </tbody>
    </nz-table>
  `
})
export class NzDemoTableAjaxComponent implements OnInit {
  pageIndex = 1;
  pageSize = 10;
  total = 1;
  listOfData: ItemData[] = [];
  loading = true;
  sortValue: string | null = null;
  sortKey: string | null = null;
  filterGender = [{ text: 'male', value: 'male' }, { text: 'female', value: 'female' }];
  searchGenderList: string[] = [];

  sort(sort: { key: string; value: string }): void {
    this.sortKey = sort.key;
    this.sortValue = sort.value;
    this.searchData();
  }

  constructor(private randomUserService: RandomUserService) {}

  searchData(reset: boolean = false): void {
    if (reset) {
      this.pageIndex = 1;
    }
    this.loading = true;
    this.randomUserService
      .getUsers(this.pageIndex, this.pageSize, this.sortKey!, this.sortValue!, this.searchGenderList)
      .subscribe(data => {
        this.loading = false;
        this.total = 200;
        this.listOfData = data.results;
      });
  }

  updateFilter(value: string[]): void {
    this.searchGenderList = value;
    this.searchData(true);
  }

  ngOnInit(): void {
    this.searchData();
  }
}

Middle size table

Name
Age
Address
John Brown32New York No. 1 Lake Park
Jim Green42London No. 1 Lake Park
Joe Black32Sidney No. 1 Lake Park

Small size table

Name
Age
Address
John Brown32New York No. 1 Lake Park
Jim Green42London No. 1 Lake Park
Joe Black32Sidney No. 1 Lake Park

两种紧凑型的列表,小型列表只用于对话框内。

expand codeexpand code
import { Component } from '@angular/core';

@Component({
  selector: 'nz-demo-table-size',
  template: `
    <h4>Middle size table</h4>
    <nz-table #middleTable nzSize="middle" [nzData]="data">
      <thead>
        <tr>
          <th>Name</th>
          <th>Age</th>
          <th>Address</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of middleTable.data">
          <td>{{ data.name }}</td>
          <td>{{ data.age }}</td>
          <td>{{ data.address }}</td>
        </tr>
      </tbody>
    </nz-table>
    <h4>Small size table</h4>
    <nz-table #smallTable nzSize="small" [nzData]="data">
      <thead>
        <tr>
          <th>Name</th>
          <th>Age</th>
          <th>Address</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of smallTable.data">
          <td>{{ data.name }}</td>
          <td>{{ data.age }}</td>
          <td>{{ data.address }}</td>
        </tr>
      </tbody>
    </nz-table>
  `,
  styles: [
    `
      h4 {
        margin-bottom: 16px;
      }
    `
  ]
})
export class NzDemoTableSizeComponent {
  data = [
    {
      key: '1',
      name: 'John Brown',
      age: 32,
      address: 'New York No. 1 Lake Park'
    },
    {
      key: '2',
      name: 'Jim Green',
      age: 42,
      address: 'London No. 1 Lake Park'
    },
    {
      key: '3',
      name: 'Joe Black',
      age: 32,
      address: 'Sidney No. 1 Lake Park'
    }
  ];
}
Header
Name
Age
Address
John Brown32New York No. 1 Lake Park
Jim Green42London No. 1 Lake Park
Joe Black32Sidney No. 1 Lake Park

添加表格边框线,页头和页脚。

expand codeexpand code
import { Component } from '@angular/core';

@Component({
  selector: 'nz-demo-table-bordered',
  template: `
    <nz-table #borderedTable nzBordered nzFooter="Footer" nzTitle="Header" [nzData]="dataSet">
      <thead>
        <tr>
          <th>Name</th>
          <th>Age</th>
          <th>Address</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of borderedTable.data">
          <td>{{ data.name }}</td>
          <td>{{ data.age }}</td>
          <td>{{ data.address }}</td>
        </tr>
      </tbody>
    </nz-table>
  `
})
export class NzDemoTableBorderedComponent {
  dataSet = [
    {
      key: '1',
      name: 'John Brown',
      age: 32,
      address: 'New York No. 1 Lake Park'
    },
    {
      key: '2',
      name: 'Jim Green',
      age: 42,
      address: 'London No. 1 Lake Park'
    },
    {
      key: '3',
      name: 'Joe Black',
      age: 32,
      address: 'Sidney No. 1 Lake Park'
    }
  ];
}
Name
Age
Address
John Brown32New York No. 1 Lake Park
Jim Green42London No. 1 Lake Park
Joe Black32Sidney No. 1 Lake Park

当表格内容较多不能一次性完全展示时,可以通过 td 上的 nzExpand 属性展开。

expand codeexpand code
import { Component } from '@angular/core';

@Component({
  selector: 'nz-demo-table-expand',
  template: `
    <nz-table #nzTable [nzData]="listOfData">
      <thead>
        <tr>
          <th nzShowExpand></th>
          <th>Name</th>
          <th>Age</th>
          <th>Address</th>
        </tr>
      </thead>
      <tbody>
        <ng-template ngFor let-data [ngForOf]="nzTable.data">
          <tr>
            <td nzShowExpand [(nzExpand)]="mapOfExpandData[data.id]"></td>
            <td>{{ data.name }}</td>
            <td>{{ data.age }}</td>
            <td>{{ data.address }}</td>
          </tr>
          <tr [nzExpand]="mapOfExpandData[data.id]">
            <td></td>
            <td colspan="3">{{ data.description }}</td>
          </tr>
        </ng-template>
      </tbody>
    </nz-table>
  `
})
export class NzDemoTableExpandComponent {
  mapOfExpandData: { [key: string]: boolean } = {};
  listOfData = [
    {
      id: 1,
      name: 'John Brown',
      age: 32,
      expand: false,
      address: 'New York No. 1 Lake Park',
      description: 'My name is John Brown, I am 32 years old, living in New York No. 1 Lake Park.'
    },
    {
      id: 2,
      name: 'Jim Green',
      age: 42,
      expand: false,
      address: 'London No. 1 Lake Park',
      description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.'
    },
    {
      id: 3,
      name: 'Joe Black',
      age: 32,
      expand: false,
      address: 'Sidney No. 1 Lake Park',
      description: 'My name is Joe Black, I am 32 years old, living in Sidney No. 1 Lake Park.'
    }
  ];
}
Name
Age
Home phone
Address
John Brown320571-2209890918889898989New York No. 1 Lake Park
Jim Green420571-2209833318889898888London No. 1 Lake Park
Joe Black320575-2209890918900010002Sidney No. 1 Lake Park
Jim Red1818900010002London No. 2 Lake Park
Jake White18

W3C标准 <table> 一样,使用 colspanrowspan 合并行/列。

expand codeexpand code
import { Component } from '@angular/core';

@Component({
  selector: 'nz-demo-table-colspan-rowspan',
  template: `
    <nz-table #colSpanTable [nzData]="listOfData" nzBordered>
      <thead>
        <tr>
          <th>Name</th>
          <th>Age</th>
          <th colspan="2">Home phone</th>
          <th>Address</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of colSpanTable.data; index as i">
          <td>{{ data.name }}</td>
          <td [attr.colspan]="i === 4 ? 5 : 1">{{ data.age }}</td>
          <td [attr.rowspan]="i === 2 ? 2 : 1" *ngIf="i !== 3 && i !== 4">{{ data.tel }}</td>
          <td *ngIf="i !== 4">{{ data.phone }}</td>
          <td *ngIf="i !== 4">{{ data.address }}</td>
        </tr>
      </tbody>
    </nz-table>
  `
})
export class NzDemoTableColspanRowspanComponent {
  listOfData = [
    {
      key: '1',
      name: 'John Brown',
      age: 32,
      tel: '0571-22098909',
      phone: 18889898989,
      address: 'New York No. 1 Lake Park'
    },
    {
      key: '2',
      name: 'Jim Green',
      tel: '0571-22098333',
      phone: 18889898888,
      age: 42,
      address: 'London No. 1 Lake Park'
    },
    {
      key: '3',
      name: 'Joe Black',
      age: 32,
      tel: '0575-22098909',
      phone: 18900010002,
      address: 'Sidney No. 1 Lake Park'
    },
    {
      key: '4',
      name: 'Jim Red',
      age: 18,
      tel: '0575-22098909',
      phone: 18900010002,
      address: 'London No. 2 Lake Park'
    },
    {
      key: '5',
      name: 'Jake White',
      age: 18,
      tel: '0575-22098909',
      phone: 18900010002,
      address: 'Dublin No. 2 Lake Park'
    }
  ];
}
Name
Age
Address
John Brown sr. 60New York No. 1 Lake Park
Joe Black 32Sidney No. 1 Lake Park

表格支持树形数据的展示,可以通过设置 nzIndentSize 以控制每一层的缩进宽度,本例子中提供了树与数组之间的转换函数,实际业务中请根据需求修改。

expand codeexpand code
import { Component, OnInit } from '@angular/core';

export interface TreeNodeInterface {
  key: number;
  name: string;
  age?: number;
  level?: number;
  expand?: boolean;
  address?: string;
  children?: TreeNodeInterface[];
  parent?: TreeNodeInterface;
}

@Component({
  selector: 'nz-demo-table-expand-children',
  template: `
    <nz-table #expandTable [nzData]="listOfMapData">
      <thead>
        <tr>
          <th nzWidth="40%">Name</th>
          <th nzWidth="30%">Age</th>
          <th>Address</th>
        </tr>
      </thead>
      <tbody>
        <ng-container *ngFor="let data of expandTable.data">
          <ng-container *ngFor="let item of mapOfExpandedData[data.key]">
            <tr *ngIf="(item.parent && item.parent.expand) || !item.parent">
              <td
                [nzIndentSize]="item.level * 20"
                [nzShowExpand]="!!item.children"
                [(nzExpand)]="item.expand"
                (nzExpandChange)="collapse(mapOfExpandedData[data.key], item, $event)"
              >
                {{ item.name }}
              </td>
              <td>{{ item.age }}</td>
              <td>{{ item.address }}</td>
            </tr>
          </ng-container>
        </ng-container>
      </tbody>
    </nz-table>
  `
})
export class NzDemoTableExpandChildrenComponent implements OnInit {
  listOfMapData: TreeNodeInterface[] = [
    {
      key: 1,
      name: 'John Brown sr.',
      age: 60,
      address: 'New York No. 1 Lake Park',
      children: [
        {
          key: 11,
          name: 'John Brown',
          age: 42,
          address: 'New York No. 2 Lake Park'
        },
        {
          key: 12,
          name: 'John Brown jr.',
          age: 30,
          address: 'New York No. 3 Lake Park',
          children: [
            {
              key: 121,
              name: 'Jimmy Brown',
              age: 16,
              address: 'New York No. 3 Lake Park'
            }
          ]
        },
        {
          key: 13,
          name: 'Jim Green sr.',
          age: 72,
          address: 'London No. 1 Lake Park',
          children: [
            {
              key: 131,
              name: 'Jim Green',
              age: 42,
              address: 'London No. 2 Lake Park',
              children: [
                {
                  key: 1311,
                  name: 'Jim Green jr.',
                  age: 25,
                  address: 'London No. 3 Lake Park'
                },
                {
                  key: 1312,
                  name: 'Jimmy Green sr.',
                  age: 18,
                  address: 'London No. 4 Lake Park'
                }
              ]
            }
          ]
        }
      ]
    },
    {
      key: 2,
      name: 'Joe Black',
      age: 32,
      address: 'Sidney No. 1 Lake Park'
    }
  ];
  mapOfExpandedData: { [key: string]: TreeNodeInterface[] } = {};

  collapse(array: TreeNodeInterface[], data: TreeNodeInterface, $event: boolean): void {
    if ($event === false) {
      if (data.children) {
        data.children.forEach(d => {
          const target = array.find(a => a.key === d.key)!;
          target.expand = false;
          this.collapse(array, target, false);
        });
      } else {
        return;
      }
    }
  }

  convertTreeToList(root: TreeNodeInterface): TreeNodeInterface[] {
    const stack: TreeNodeInterface[] = [];
    const array: TreeNodeInterface[] = [];
    const hashMap = {};
    stack.push({ ...root, level: 0, expand: false });

    while (stack.length !== 0) {
      const node = stack.pop()!;
      this.visitNode(node, hashMap, array);
      if (node.children) {
        for (let i = node.children.length - 1; i >= 0; i--) {
          stack.push({ ...node.children[i], level: node.level! + 1, expand: false, parent: node });
        }
      }
    }

    return array;
  }

  visitNode(node: TreeNodeInterface, hashMap: { [key: string]: boolean }, array: TreeNodeInterface[]): void {
    if (!hashMap[node.key]) {
      hashMap[node.key] = true;
      array.push(node);
    }
  }

  ngOnInit(): void {
    this.listOfMapData.forEach(item => {
      this.mapOfExpandedData[item.key] = this.convertTreeToList(item);
    });
  }
}
Name
Age
Address
Edward King 032London, Park Lane no. 0
Edward King 132London, Park Lane no. 1
Edward King 232London, Park Lane no. 2
Edward King 332London, Park Lane no. 3
Edward King 432London, Park Lane no. 4
Edward King 532London, Park Lane no. 5
Edward King 632London, Park Lane no. 6
Edward King 732London, Park Lane no. 7
Edward King 832London, Park Lane no. 8
Edward King 932London, Park Lane no. 9
Edward King 1032London, Park Lane no. 10
Edward King 1132London, Park Lane no. 11
Edward King 1232London, Park Lane no. 12
Edward King 1332London, Park Lane no. 13
Edward King 1432London, Park Lane no. 14
Edward King 1532London, Park Lane no. 15
Edward King 1632London, Park Lane no. 16
Edward King 1732London, Park Lane no. 17
Edward King 1832London, Park Lane no. 18
Edward King 1932London, Park Lane no. 19
Edward King 2032London, Park Lane no. 20
Edward King 2132London, Park Lane no. 21
Edward King 2232London, Park Lane no. 22
Edward King 2332London, Park Lane no. 23
Edward King 2432London, Park Lane no. 24
Edward King 2532London, Park Lane no. 25
Edward King 2632London, Park Lane no. 26
Edward King 2732London, Park Lane no. 27
Edward King 2832London, Park Lane no. 28
Edward King 2932London, Park Lane no. 29
Edward King 3032London, Park Lane no. 30
Edward King 3132London, Park Lane no. 31
Edward King 3232London, Park Lane no. 32
Edward King 3332London, Park Lane no. 33
Edward King 3432London, Park Lane no. 34
Edward King 3532London, Park Lane no. 35
Edward King 3632London, Park Lane no. 36
Edward King 3732London, Park Lane no. 37
Edward King 3832London, Park Lane no. 38
Edward King 3932London, Park Lane no. 39
Edward King 4032London, Park Lane no. 40
Edward King 4132London, Park Lane no. 41
Edward King 4232London, Park Lane no. 42
Edward King 4332London, Park Lane no. 43
Edward King 4432London, Park Lane no. 44
Edward King 4532London, Park Lane no. 45
Edward King 4632London, Park Lane no. 46
Edward King 4732London, Park Lane no. 47
Edward King 4832London, Park Lane no. 48
Edward King 4932London, Park Lane no. 49

方便一页内展示大量数据。

需要指定 thnzWidth 属性,否则列头和内容可能不对齐。

expand codeexpand code
import { Component, OnInit } from '@angular/core';

interface ItemData {
  name: string;
  age: number;
  address: string;
}

@Component({
  selector: 'nz-demo-table-fixed-header',
  template: `
    <nz-table #headerTable [nzData]="listOfData" [nzPageSize]="50" [nzScroll]="{ y: '240px' }">
      <thead>
        <tr>
          <th nzWidth="150px">Name</th>
          <th nzWidth="150px">Age</th>
          <th>Address</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of headerTable.data">
          <td>{{ data.name }}</td>
          <td>{{ data.age }}</td>
          <td>{{ data.address }}</td>
        </tr>
      </tbody>
    </nz-table>
  `
})
export class NzDemoTableFixedHeaderComponent implements OnInit {
  listOfData: ItemData[] = [];

  ngOnInit(): void {
    for (let i = 0; i < 100; i++) {
      this.listOfData.push({
        name: `Edward King ${i}`,
        age: 32,
        address: `London, Park Lane no. ${i}`
      });
    }
  }
}
Full Name
Age
Column 1
Column 2
Column 3
Column 4
Column 5
Column 6
Column 7
Column 8
Action
John Brown32New YorkNew YorkNew YorkNew YorkNew YorkNew YorkNew YorkNew Yorkaction
Jim Green40LondonLondonLondonLondonLondonLondonLondonLondonaction

对于列数很多的数据,可以使用 nzLeftnzRight 固定前后的列,横向滚动查看其它数据,需要和 nzScroll.x 配合使用。

固定列使用了 sticky 属性,浏览器支持情况可以参考这里

若列头与内容不对齐或出现列重复,请指定每一列的 th 的宽度 nzWidth

建议指定 nzScroll.x 为大于表格宽度的固定值或百分比。注意,且非固定列宽度之和不要超过 nzScroll.x

expand codeexpand code
import { Component } from '@angular/core';

@Component({
  selector: 'nz-demo-table-fixed-columns',
  template: `
    <nz-table #columnTable [nzData]="listOfData" [nzScroll]="{ x: '1100px' }">
      <thead>
        <tr>
          <th nzWidth="100px" nzLeft="0px">Full Name</th>
          <th nzWidth="100px" nzLeft="100px">Age</th>
          <th nzWidth="100px">Column 1</th>
          <th nzWidth="100px">Column 2</th>
          <th nzWidth="100px">Column 3</th>
          <th nzWidth="100px">Column 4</th>
          <th nzWidth="100px">Column 5</th>
          <th nzWidth="100px">Column 6</th>
          <th nzWidth="100px">Column 7</th>
          <th nzRight="100px" nzWidth="100px">Column 8</th>
          <th nzWidth="100px" nzRight="0px">Action</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of columnTable.data">
          <td nzLeft="0px">{{ data.name }}</td>
          <td nzLeft="100px">{{ data.age }}</td>
          <td>{{ data.address }}</td>
          <td>{{ data.address }}</td>
          <td>{{ data.address }}</td>
          <td>{{ data.address }}</td>
          <td>{{ data.address }}</td>
          <td>{{ data.address }}</td>
          <td>{{ data.address }}</td>
          <td nzRight="100px">{{ data.address }}</td>
          <td nzRight="0px">
            <a>action</a>
          </td>
        </tr>
      </tbody>
    </nz-table>
  `
})
export class NzDemoTableFixedColumnsComponent {
  listOfData = [
    {
      key: '1',
      name: 'John Brown',
      age: 32,
      address: 'New York'
    },
    {
      key: '2',
      name: 'Jim Green',
      age: 40,
      address: 'London'
    }
  ];
}
Full Name
Age
Column 1
Column 2
Column 3
Column 4
Column 5
Column 6
Column 7
Column 8
Action
Edward King 032LondonLondonLondonLondonLondonLondonLondonLondonaction
Edward King 132LondonLondonLondonLondonLondonLondonLondonLondonaction
Edward King 232LondonLondonLondonLondonLondonLondonLondonLondonaction
Edward King 332LondonLondonLondonLondonLondonLondonLondonLondonaction
Edward King 432LondonLondonLondonLondonLondonLondonLondonLondonaction
Edward King 532LondonLondonLondonLondonLondonLondonLondonLondonaction
Edward King 632LondonLondonLondonLondonLondonLondonLondonLondonaction
Edward King 732LondonLondonLondonLondonLondonLondonLondonLondonaction
Edward King 832LondonLondonLondonLondonLondonLondonLondonLondonaction
Edward King 932LondonLondonLondonLondonLondonLondonLondonLondonaction

适合同时展示有大量数据和数据列。

固定列使用了 sticky 属性,浏览器支持情况可以参考这里

若列头与内容不对齐或出现列重复,请指定列的宽度 nzWidth

建议指定 nzScroll.x 为大于表格宽度的固定值或百分比。注意,且非固定列宽度之和不要超过 nzScroll.x

expand codeexpand code
import { Component, OnInit } from '@angular/core';

interface ItemData {
  name: string;
  age: number;
  address: string;
}

@Component({
  selector: 'nz-demo-table-fixed-columns-header',
  template: `
    <nz-table #fixedTable [nzData]="listOfData" [nzScroll]="{ x: '1150px', y: '240px' }">
      <thead>
        <tr>
          <th nzWidth="150px" nzLeft="0px">Full Name</th>
          <th nzWidth="100px" nzLeft="150px">Age</th>
          <th nzWidth="100px">Column 1</th>
          <th nzWidth="100px">Column 2</th>
          <th nzWidth="100px">Column 3</th>
          <th nzWidth="100px">Column 4</th>
          <th nzWidth="100px">Column 5</th>
          <th nzWidth="100px">Column 6</th>
          <th nzWidth="100px">Column 7</th>
          <th nzWidth="100px">Column 8</th>
          <th nzWidth="100px" nzRight="0px">Action</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of fixedTable.data">
          <td nzLeft="0px">{{ data.name }}</td>
          <td nzLeft="150px">{{ data.age }}</td>
          <td>{{ data.address }}</td>
          <td>{{ data.address }}</td>
          <td>{{ data.address }}</td>
          <td>{{ data.address }}</td>
          <td>{{ data.address }}</td>
          <td>{{ data.address }}</td>
          <td>{{ data.address }}</td>
          <td>{{ data.address }}</td>
          <td nzRight="0px">
            <a>action</a>
          </td>
        </tr>
      </tbody>
    </nz-table>
  `
})
export class NzDemoTableFixedColumnsHeaderComponent implements OnInit {
  listOfData: ItemData[] = [];

  ngOnInit(): void {
    for (let i = 0; i < 100; i++) {
      this.listOfData.push({
        name: `Edward King ${i}`,
        age: 32,
        address: `London`
      });
    }
  }
}
Name
Other
Company
Gender
Age
Address
Company Address
Company Name
Street
Block
Building
Door No.
John Brown1Lake ParkC2035Lake Street 42SoftLake CoM
John Brown2Lake ParkC2035Lake Street 42SoftLake CoM
John Brown3Lake ParkC2035Lake Street 42SoftLake CoM
John Brown4Lake ParkC2035Lake Street 42SoftLake CoM
John Brown5Lake ParkC2035Lake Street 42SoftLake CoM
John Brown6Lake ParkC2035Lake Street 42SoftLake CoM
John Brown7Lake ParkC2035Lake Street 42SoftLake CoM
John Brown8Lake ParkC2035Lake Street 42SoftLake CoM
John Brown9Lake ParkC2035Lake Street 42SoftLake CoM
John Brown10Lake ParkC2035Lake Street 42SoftLake CoM

当使用分组表头时,thnzWidth 方式不再适用,使用 nzWidthConfig 来设定每个分组的宽度

expand codeexpand code
import { Component, OnInit } from '@angular/core';

interface ItemData {
  name: string;
  age: number;
  street: string;
  building: string;
  number: number;
  companyAddress: string;
  companyName: string;
  gender: string;
}

@Component({
  selector: 'nz-demo-table-grouping-columns',
  template: `
    <nz-table
      #groupingTable
      [nzData]="listOfDisplayData"
      nzBordered
      nzSize="middle"
      [nzWidthConfig]="widthConfig"
      [nzScroll]="scrollConfig"
    >
      <thead>
        <tr>
          <th rowspan="4" nzLeft="0px" nzShowFilter [nzFilters]="filterName" (nzFilterChange)="search($event)">Name</th>
          <th colspan="4">Other</th>
          <th colspan="2">Company</th>
          <th rowspan="4" nzRight="0px">Gender</th>
        </tr>
        <tr>
          <th rowspan="3" nzShowSort [(nzSort)]="sortValue" (nzSortChange)="search(searchName)">Age</th>
          <th colspan="3">Address</th>
          <th rowspan="3">Company Address</th>
          <th rowspan="3">Company Name</th>
        </tr>
        <tr>
          <th rowspan="2">Street</th>
          <th colspan="2">Block</th>
        </tr>
        <tr>
          <th>Building</th>
          <th>Door No.</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of groupingTable.data">
          <td nzLeft="0px">{{ data.name }}</td>
          <td>{{ data.age }}</td>
          <td>{{ data.street }}</td>
          <td>{{ data.building }}</td>
          <td>{{ data.number }}</td>
          <td>{{ data.companyAddress }}</td>
          <td>{{ data.companyName }}</td>
          <td nzRight="0px">{{ data.gender }}</td>
        </tr>
      </tbody>
    </nz-table>
  `
})
export class NzDemoTableGroupingColumnsComponent implements OnInit {
  widthConfig = ['100px', '200px', '200px', '100px', '100px', '200px', '200px', '100px'];
  scrollConfig = { x: '1200px', y: '240px' };
  listOfDisplayData: ItemData[] = [];
  listOfData: ItemData[] = [];
  sortValue: 'ascend' | 'descend' | null = null;
  filterName = [{ text: 'Joe', value: 'Joe' }, { text: 'John', value: 'John' }];
  searchName: string[] = [];

  search(searchName: string[]): void {
    this.searchName = searchName;
    const filterFunc = (item: ItemData) => {
      return this.searchName.length ? this.searchName.some(name => item.name.indexOf(name) !== -1) : true;
    };
    const listOfData = this.listOfData.filter(item => filterFunc(item));
    this.listOfDisplayData = listOfData.sort((a, b) =>
      this.sortValue === 'ascend' ? (a.age > b.age ? 1 : -1) : b.age > a.age ? 1 : -1
    );
  }

  ngOnInit(): void {
    for (let i = 0; i < 100; i++) {
      this.listOfData.push({
        name: 'John Brown',
        age: i + 1,
        street: 'Lake Park',
        building: 'C',
        number: 2035,
        companyAddress: 'Lake Street 42',
        companyName: 'SoftLake Co',
        gender: 'M'
      });
    }
    this.listOfDisplayData = [...this.listOfData];
  }
}
Name
Age
Address
Action
Edward King 0
32London, Park Lane no. 0Delete
Edward King 1
32London, Park Lane no. 1Delete

定制带单元格编辑功能的表格,自由操作单元格内容。

expand codeexpand code
import { Component, ElementRef, HostListener, OnInit, ViewChild } from '@angular/core';
import { NzInputDirective } from 'ng-zorro-antd/input';

interface ItemData {
  id: string;
  name: string;
  age: string;
  address: string;
}

@Component({
  selector: 'nz-demo-table-edit-cell',
  template: `
    <button nz-button (click)="addRow()" nzType="primary">Add</button>
    <nz-table #editRowTable nzBordered [nzData]="listOfData">
      <thead>
        <tr>
          <th nzWidth="30%">Name</th>
          <th>Age</th>
          <th>Address</th>
          <th>Action</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of editRowTable.data" class="editable-row">
          <td>
            <div class="editable-cell" *ngIf="editId !== data.id; else editTpl">
              <div class="editable-cell-value-wrap" (click)="startEdit(data.id, $event)">
                {{ data.name }}
              </div>
            </div>
            <ng-template #editTpl>
              <input type="text" nz-input [(ngModel)]="data.name" />
            </ng-template>
          </td>
          <td>{{ data.age }}</td>
          <td>{{ data.address }}</td>
          <td>
            <a nz-popconfirm nzTitle="Sure to delete?" (nzOnConfirm)="deleteRow(data.id)">Delete</a>
          </td>
        </tr>
      </tbody>
    </nz-table>
  `,
  styles: [
    `
      button {
        margin-bottom: 16px;
      }

      .editable-cell {
        position: relative;
      }

      .editable-cell-value-wrap {
        padding: 5px 12px;
        cursor: pointer;
      }

      .editable-row:hover .editable-cell-value-wrap {
        border: 1px solid #d9d9d9;
        border-radius: 4px;
        padding: 4px 11px;
      }
    `
  ]
})
export class NzDemoTableEditCellComponent implements OnInit {
  i = 0;
  editId: string | null;
  listOfData: ItemData[] = [];
  @ViewChild(NzInputDirective, { static: false, read: ElementRef }) inputElement: ElementRef;

  @HostListener('window:click', ['$event'])
  handleClick(e: MouseEvent): void {
    if (this.editId && this.inputElement && this.inputElement.nativeElement !== e.target) {
      this.editId = null;
    }
  }

  addRow(): void {
    this.listOfData = [
      ...this.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 = this.listOfData.filter(d => d.id !== id);
  }

  startEdit(id: string, event: MouseEvent): void {
    event.preventDefault();
    event.stopPropagation();
    this.editId = id;
  }

  ngOnInit(): void {
    this.addRow();
    this.addRow();
  }
}
Name
Age
Address
Action
Edrward 0 32 London Park no. 0
Edrward 1 32 London Park no. 1
Edrward 2 32 London Park no. 2
Edrward 3 32 London Park no. 3
Edrward 4 32 London Park no. 4
Edrward 5 32 London Park no. 5
Edrward 6 32 London Park no. 6
Edrward 7 32 London Park no. 7
Edrward 8 32 London Park no. 8
Edrward 9 32 London Park no. 9

定制带行编辑功能的表格,自由操作行内容。

expand codeexpand code
import { Component, OnInit } from '@angular/core';

interface ItemData {
  id: string;
  name: string;
  age: number;
  address: string;
}

@Component({
  selector: 'nz-demo-table-edit-row',
  template: `
    <nz-table #editRowTable nzBordered [nzData]="listOfData">
      <thead>
        <tr>
          <th nzWidth="25%">Name</th>
          <th nzWidth="15%">Age</th>
          <th nzWidth="40%">Address</th>
          <th>Action</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of editRowTable.data">
          <td>
            <ng-container *ngIf="!editCache[data.id].edit; else nameInputTpl">
              {{ data.name }}
            </ng-container>
            <ng-template #nameInputTpl>
              <input type="text" nz-input [(ngModel)]="editCache[data.id].data.name" />
            </ng-template>
          </td>
          <td>
            <ng-container *ngIf="!editCache[data.id].edit; else ageInputTpl">
              {{ data.age }}
            </ng-container>
            <ng-template #ageInputTpl>
              <input type="text" nz-input [(ngModel)]="editCache[data.id].data.age" />
            </ng-template>
          </td>
          <td>
            <ng-container *ngIf="!editCache[data.id].edit; else addressInputTpl">
              {{ data.address }}
            </ng-container>
            <ng-template #addressInputTpl>
              <input type="text" nz-input [(ngModel)]="editCache[data.id].data.address" />
            </ng-template>
          </td>
          <td>
            <div class="editable-row-operations">
              <ng-container *ngIf="!editCache[data.id].edit; else saveTpl">
                <a (click)="startEdit(data.id)">Edit</a>
              </ng-container>
              <ng-template #saveTpl>
                <a (click)="saveEdit(data.id)">Save</a>
                <a nz-popconfirm nzTitle="Sure to cancel?" (nzOnConfirm)="cancelEdit(data.id)">Cancel</a>
              </ng-template>
            </div>
          </td>
        </tr>
      </tbody>
    </nz-table>
  `,
  styles: [
    `
      .editable-row-operations a {
        margin-right: 8px;
      }
    `
  ]
})
export class NzDemoTableEditRowComponent implements OnInit {
  editCache: { [key: string]: { edit: boolean; data: ItemData } } = {};
  listOfData: ItemData[] = [];

  startEdit(id: string): void {
    this.editCache[id].edit = true;
  }

  cancelEdit(id: string): void {
    const index = this.listOfData.findIndex(item => item.id === id);
    this.editCache[id] = {
      data: { ...this.listOfData[index] },
      edit: false
    };
  }

  saveEdit(id: string): void {
    const index = this.listOfData.findIndex(item => item.id === id);
    Object.assign(this.listOfData[index], this.editCache[id].data);
    this.editCache[id].edit = false;
  }

  updateEditCache(): void {
    this.listOfData.forEach(item => {
      this.editCache[item.id] = {
        edit: false,
        data: { ...item }
      };
    });
  }

  ngOnInit(): void {
    for (let i = 0; i < 100; i++) {
      this.listOfData.push({
        id: `${i}`,
        name: `Edrward ${i}`,
        age: 32,
        address: `London Park no. ${i}`
      });
    }
    this.updateEditCache();
  }
}


Full Name
Age
Index
Column 1
Column 2
Column 3
Column 4
Column 5
Column 6
Column 7
Column 8
Action

虚拟滚动,结合 cdk scrolling 的虚拟滚动,用于巨量数据加载。可以通过获得 cdkVirtualScrollViewport 进行进一步操作,见本示例及 API

expand codeexpand code
import { AfterViewInit, Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { NzTableComponent } from 'ng-zorro-antd/table';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

export interface VirtualDataInterface {
  index: number;
  name: string;
  age: number;
  address: string;
}

@Component({
  selector: 'nz-demo-table-virtual',
  template: `
    <button nz-button (click)="scrollToIndex(200)">Scroll To Index 200</button>
    <br />
    <br />
    <nz-table
      #virtualTable
      nzVirtualScroll
      [nzVirtualItemSize]="54"
      [nzData]="listOfData"
      [nzVirtualForTrackBy]="trackByIndex"
      [nzFrontPagination]="false"
      [nzShowPagination]="false"
      [nzScroll]="{ x: '1300px', y: '240px' }"
    >
      <thead>
        <tr>
          <th nzWidth="200px" nzLeft="0px">Full Name</th>
          <th nzWidth="100px" nzLeft="200px">Age</th>
          <th nzWidth="100px">Index</th>
          <th nzWidth="100px">Column 1</th>
          <th nzWidth="100px">Column 2</th>
          <th nzWidth="100px">Column 3</th>
          <th nzWidth="100px">Column 4</th>
          <th nzWidth="100px">Column 5</th>
          <th nzWidth="100px">Column 6</th>
          <th nzWidth="100px">Column 7</th>
          <th nzWidth="100px">Column 8</th>
          <th nzWidth="100px" nzRight="0px">Action</th>
        </tr>
      </thead>
      <tbody>
        <ng-template nz-virtual-scroll let-data let-index="index">
          <tr>
            <td nzLeft="0px">{{ data.name }} {{ index }}</td>
            <td nzLeft="200px">{{ data.age }}</td>
            <td>{{ data.index }}</td>
            <td>{{ data.address }}</td>
            <td>{{ data.address }}</td>
            <td>{{ data.address }}</td>
            <td>{{ data.address }}</td>
            <td>{{ data.address }}</td>
            <td>{{ data.address }}</td>
            <td>{{ data.address }}</td>
            <td>{{ data.address }}</td>
            <td nzRight="0px">
              <a>action</a>
            </td>
          </tr>
        </ng-template>
      </tbody>
    </nz-table>
  `
})
export class NzDemoTableVirtualComponent implements OnInit, AfterViewInit, OnDestroy {
  @ViewChild('virtualTable', { static: false }) nzTableComponent: NzTableComponent;
  private destroy$ = new Subject();
  listOfData: VirtualDataInterface[] = [];

  scrollToIndex(index: number): void {
    this.nzTableComponent.cdkVirtualScrollViewport.scrollToIndex(index);
  }

  trackByIndex(_: number, data: VirtualDataInterface): number {
    return data.index;
  }

  ngOnInit(): void {
    const data = [];
    for (let i = 0; i < 20000; i++) {
      data.push({
        index: i,
        name: `Edward King`,
        age: 32,
        address: `London`
      });
    }
    this.listOfData = data;
  }

  ngAfterViewInit(): void {
    this.nzTableComponent.cdkVirtualScrollViewport.scrolledIndexChange
      .pipe(takeUntil(this.destroy$))
      .subscribe((data: number) => {
        console.log('scroll index to', data);
      });
  }

  ngOnDestroy(): void {
    this.destroy$.next();
    this.destroy$.complete();
  }
}
Name
Platform
Version
Upgraded
Creator
Date
Action
ScreemiOS10.3.4.5654500Jack2014-12-24 23:12:00Publish
ScreemiOS10.3.4.5654500Jack2014-12-24 23:12:00Publish
ScreemiOS10.3.4.5654500Jack2014-12-24 23:12:00Publish

展示每行数据更详细的信息。

expand codeexpand code
import { Component, OnInit } from '@angular/core';

interface ParentItemData {
  key: number;
  name: string;
  platform: string;
  version: string;
  upgradeNum: number | string;
  creator: string;
  createdAt: string;
  expand: boolean;
}

interface ChildrenItemData {
  key: number;
  name: string;
  date: string;
  upgradeNum: string;
}

@Component({
  selector: 'nz-demo-table-nested-table',
  template: `
    <nz-table #nestedTable [nzData]="listOfParentData" [nzPageSize]="10">
      <thead>
        <tr>
          <th nzShowExpand></th>
          <th>Name</th>
          <th>Platform</th>
          <th>Version</th>
          <th>Upgraded</th>
          <th>Creator</th>
          <th>Date</th>
          <th>Action</th>
        </tr>
      </thead>
      <tbody>
        <ng-template ngFor let-data [ngForOf]="nestedTable.data">
          <tr>
            <td nzShowExpand [(nzExpand)]="data.expand"></td>
            <td>{{ data.name }}</td>
            <td>{{ data.platform }}</td>
            <td>{{ data.version }}</td>
            <td>{{ data.upgradeNum }}</td>
            <td>{{ data.creator }}</td>
            <td>{{ data.createdAt }}</td>
            <td>
              <a>Publish</a>
            </td>
          </tr>
          <tr [nzExpand]="data.expand">
            <td></td>
            <td colspan="7">
              <nz-table #innerTable [nzData]="listOfChildrenData" nzSize="middle" [nzShowPagination]="false">
                <thead>
                  <tr>
                    <th>Date</th>
                    <th>Name</th>
                    <th>Status</th>
                    <th>Upgrade Status</th>
                    <th>Action</th>
                  </tr>
                </thead>
                <tbody>
                  <tr *ngFor="let data of innerTable.data">
                    <td>{{ data.date }}</td>
                    <td>{{ data.name }}</td>
                    <td>
                      <nz-badge [nzStatus]="'success'" [nzText]="'Finished'"></nz-badge>
                    </td>
                    <td>{{ data.upgradeNum }}</td>
                    <td>
                      <span class="table-operation">
                        <a nz-dropdown class="operation" [nzDropdownMenu]="menu">
                          Pause <i nz-icon nzType="down"></i>
                        </a>
                        <nz-dropdown-menu #menu="nzDropdownMenu">
                          <ul nz-menu>
                            <li nz-menu-item>
                              <a>Action 1</a>
                            </li>
                            <li nz-menu-item>
                              <a>Action 2</a>
                            </li>
                          </ul>
                        </nz-dropdown-menu>
                        <nz-divider nzType="vertical"></nz-divider>
                        <a class="operation">Stop</a>
                        <nz-divider nzType="vertical"></nz-divider>
                        <a>More</a>
                      </span>
                    </td>
                  </tr>
                </tbody>
              </nz-table>
            </td>
          </tr>
        </ng-template>
      </tbody>
    </nz-table>
  `
})
export class NzDemoTableNestedTableComponent implements OnInit {
  listOfParentData: ParentItemData[] = [];
  listOfChildrenData: ChildrenItemData[] = [];

  ngOnInit(): void {
    for (let i = 0; i < 3; ++i) {
      this.listOfParentData.push({
        key: i,
        name: 'Screem',
        platform: 'iOS',
        version: '10.3.4.5654',
        upgradeNum: 500,
        creator: 'Jack',
        createdAt: '2014-12-24 23:12:00',
        expand: false
      });
    }
    for (let i = 0; i < 3; ++i) {
      this.listOfChildrenData.push({
        key: i,
        date: '2014-12-24 23:12:00',
        name: 'This is production name',
        upgradeNum: 'Upgraded: 56'
      });
    }
  }
}
Name
Age
Address
John Brown32New York No. 1 Lake Park
Jim Green42London No. 1 Lake Park
Joe Black32Sidney No. 1 Lake Park

使用自定义元素,我们可以集成 cdk drag-drop 来实现拖拽排序。

expand codeexpand code
import { moveItemInArray, CdkDragDrop } from '@angular/cdk/drag-drop';
import { Component } from '@angular/core';

@Component({
  selector: 'nz-demo-table-drag-sorting',
  template: `
    <nz-table [nzData]="listOfData" [nzFrontPagination]="false" [nzShowPagination]="false">
      <thead>
        <tr>
          <th>Name</th>
          <th>Age</th>
          <th>Address</th>
        </tr>
      </thead>
      <tbody cdkDropList (cdkDropListDropped)="drop($event)">
        <tr *ngFor="let data of listOfData" cdkDrag>
          <td>{{ data.name }}</td>
          <td>{{ data.age }}</td>
          <td>{{ data.address }}</td>
        </tr>
      </tbody>
    </nz-table>
  `,
  styles: [
    `
      ::ng-deep .cdk-drag-preview {
        display: table;
      }

      ::ng-deep .cdk-drag-placeholder {
        opacity: 0;
      }
    `
  ]
})
export class NzDemoTableDragSortingComponent {
  listOfData = [
    {
      key: '1',
      name: 'John Brown',
      age: 32,
      address: 'New York No. 1 Lake Park'
    },
    {
      key: '2',
      name: 'Jim Green',
      age: 42,
      address: 'London No. 1 Lake Park'
    },
    {
      key: '3',
      name: 'Joe Black',
      age: 32,
      address: 'Sidney No. 1 Lake Park'
    }
  ];

  drop(event: CdkDragDrop<string[]>): void {
    moveItemInArray(this.listOfData, event.previousIndex, event.currentIndex);
  }
}
Company
Contact
Country
Alfreds FutterkisteMaria AndersGermany
Centro comercial MoctezumaFrancisco ChangMexico
Ernst HandelRoland MendelAustria
Island TradingHelen BennettUK
Laughing Bacchus WinecellarsYoshi TannamuriCanada
Magazzini Alimentari RiunitiGiovanni RovelliItaly

模板模式,显示内容仅由模板内容控制,不再需要向 nzData 传入数据,完全像普通 table 一样使用,使用 ant-design 的样式。

expand codeexpand code
import { Component } from '@angular/core';

@Component({
  selector: 'nz-demo-table-template',
  template: `
    <nz-table nzTemplateMode>
      <thead>
        <tr>
          <th>Company</th>
          <th>Contact</th>
          <th>Country</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Alfreds Futterkiste</td>
          <td>Maria Anders</td>
          <td>Germany</td>
        </tr>
        <tr>
          <td>Centro comercial Moctezuma</td>
          <td>Francisco Chang</td>
          <td>Mexico</td>
        </tr>
        <tr>
          <td>Ernst Handel</td>
          <td>Roland Mendel</td>
          <td>Austria</td>
        </tr>
        <tr>
          <td>Island Trading</td>
          <td>Helen Bennett</td>
          <td>UK</td>
        </tr>
        <tr>
          <td>Laughing Bacchus Winecellars</td>
          <td>Yoshi Tannamuri</td>
          <td>Canada</td>
        </tr>
        <tr>
          <td>Magazzini Alimentari Riuniti</td>
          <td>Giovanni Rovelli</td>
          <td>Italy</td>
        </tr>
      </tbody>
    </nz-table>
  `
})
export class NzDemoTableTemplateComponent {}
Full Name
Age
Column 1
Column 2
Column 3
Column 4
Column 5
Column 6
Column 7
Column 8
Action
Edward King 0 Edward King 0 Edward King 032LondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonaction
Edward King 1 Edward King 1 Edward King 132LondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonaction
Edward King 2 Edward King 2 Edward King 232LondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonaction
Edward King 3 Edward King 3 Edward King 332LondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonaction
Edward King 4 Edward King 4 Edward King 432LondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonaction
Edward King 5 Edward King 5 Edward King 532LondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonaction
Edward King 6 Edward King 6 Edward King 632LondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonaction
Edward King 7 Edward King 7 Edward King 732LondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonaction
Edward King 8 Edward King 8 Edward King 832LondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonaction
Edward King 9 Edward King 9 Edward King 932LondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonLondonaction

td 内容超出 nzWidth 设定值时使用 nzBreakWord 折行显示

expand codeexpand code
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'nz-demo-table-break-word',
  template: `
    <nz-table #fixedTable [nzData]="listOfData" [nzScroll]="{ x: '1150px', y: '240px' }">
      <thead>
        <tr>
          <th nzWidth="150px" nzLeft="0px">Full Name</th>
          <th nzWidth="100px" nzLeft="150px">Age</th>
          <th nzWidth="100px">Column 1</th>
          <th nzWidth="100px">Column 2</th>
          <th nzWidth="100px">Column 3</th>
          <th nzWidth="100px">Column 4</th>
          <th nzWidth="100px">Column 5</th>
          <th nzWidth="100px">Column 6</th>
          <th nzWidth="100px">Column 7</th>
          <th nzWidth="100px">Column 8</th>
          <th nzWidth="100px" nzRight="0px">Action</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let data of fixedTable.data">
          <td nzBreakWord nzLeft="0px">{{ data.name }}</td>
          <td nzBreakWord nzLeft="150px">{{ data.age }}</td>
          <td nzBreakWord>{{ data.address }}</td>
          <td nzBreakWord>{{ data.address }}</td>
          <td nzBreakWord>{{ data.address }}</td>
          <td nzBreakWord>{{ data.address }}</td>
          <td nzBreakWord>{{ data.address }}</td>
          <td nzBreakWord>{{ data.address }}</td>
          <td nzBreakWord>{{ data.address }}</td>
          <td nzBreakWord>{{ data.address }}</td>
          <td nzBreakWord nzRight="0px">
            <a>action</a>
          </td>
        </tr>
      </tbody>
    </nz-table>
  `
})
export class NzDemoTableBreakWordComponent implements OnInit {
  listOfData: any[] = [];

  ngOnInit(): void {
    for (let i = 0; i < 100; i++) {
      this.listOfData.push({
        name: `Edward King ${i} Edward King ${i} Edward King ${i}`,
        age: 32,
        address: `LondonLondonLondonLondonLondon`
      });
    }
  }
}
Here is Title
Name
Age
Address
Action
John Brown12New York No. 1 Lake ParkAction 一 John BrownDelete
John Brown22New York No. 2 Lake ParkAction 一 John BrownDelete
John Brown32New York No. 3 Lake ParkAction 一 John BrownDelete
John Brown42New York No. 4 Lake ParkAction 一 John BrownDelete
John Brown52New York No. 5 Lake ParkAction 一 John BrownDelete
John Brown62New York No. 6 Lake ParkAction 一 John BrownDelete
John Brown72New York No. 7 Lake ParkAction 一 John BrownDelete
John Brown82New York No. 8 Lake ParkAction 一 John BrownDelete
John Brown92New York No. 9 Lake ParkAction 一 John BrownDelete
John Brown102New York No. 10 Lake ParkAction 一 John BrownDelete

选择不同配置组合查看效果。

expand codeexpand code
import { Component, OnInit } from '@angular/core';

interface ItemData {
  name: string;
  age: number | string;
  address: string;
  checked: boolean;
  expand: boolean;
  description: string;
  disabled?: boolean;
}

@Component({
  selector: 'nz-demo-table-dynamic-settings',
  template: `
    <div class="components-table-demo-control-bar">
      <form nz-form nzLayout="inline">
        <nz-form-item>
          <nz-form-label><label>Bordered</label></nz-form-label>
          <nz-form-control><nz-switch [(ngModel)]="bordered" name="bordered"></nz-switch></nz-form-control>
        </nz-form-item>
        <nz-form-item>
          <nz-form-label><label>Loading</label></nz-form-label>
          <nz-form-control><nz-switch [(ngModel)]="loading" name="loading"></nz-switch></nz-form-control>
        </nz-form-item>
        <nz-form-item>
          <nz-form-label><label>Pagination</label></nz-form-label>
          <nz-form-control><nz-switch [(ngModel)]="pagination" name="pagination"></nz-switch></nz-form-control>
        </nz-form-item>
        <nz-form-item>
          <nz-form-label><label>PageSizeChanger</label></nz-form-label>
          <nz-form-control><nz-switch [(ngModel)]="sizeChanger" name="sizeChanger"></nz-switch></nz-form-control>
        </nz-form-item>
        <nz-form-item>
          <nz-form-label><label>Title</label></nz-form-label>
          <nz-form-control><nz-switch [(ngModel)]="title" name="title"></nz-switch></nz-form-control>
        </nz-form-item>
        <nz-form-item>
          <nz-form-label><label>Column Header</label></nz-form-label>
          <nz-form-control><nz-switch [(ngModel)]="header" name="header"></nz-switch></nz-form-control>
        </nz-form-item>
        <nz-form-item>
          <nz-form-label><label>Footer</label></nz-form-label>
          <nz-form-control><nz-switch [(ngModel)]="footer" name="footer"></nz-switch></nz-form-control>
        </nz-form-item>
        <nz-form-item>
          <nz-form-label><label>Expandable</label></nz-form-label>
          <nz-form-control><nz-switch [(ngModel)]="expandable" name="expandable"></nz-switch></nz-form-control>
        </nz-form-item>
        <nz-form-item>
          <nz-form-label><label>Checkbox</label></nz-form-label>
          <nz-form-control><nz-switch [(ngModel)]="checkbox" name="checkbox"></nz-switch></nz-form-control>
        </nz-form-item>
        <nz-form-item>
          <nz-form-label><label>Fixed Header</label></nz-form-label>
          <nz-form-control><nz-switch [(ngModel)]="fixHeader" name="fixHeader"></nz-switch></nz-form-control>
        </nz-form-item>
        <nz-form-item>
          <nz-form-label><label>No Result</label></nz-form-label>
          <nz-form-control
            ><nz-switch [(ngModel)]="noResult" (ngModelChange)="noResultChange($event)" name="noResult"></nz-switch
          ></nz-form-control>
        </nz-form-item>
        <nz-form-item>
          <nz-form-label><label>Simple Pagination</label></nz-form-label>
          <nz-form-control><nz-switch [(ngModel)]="simple" name="simple"></nz-switch></nz-form-control>
        </nz-form-item>
        <nz-form-item>
          <nz-form-label><label>Size</label></nz-form-label>
          <nz-form-control>
            <nz-radio-group [(ngModel)]="size" name="size">
              <label nz-radio-button nzValue="default">Default</label>
              <label nz-radio-button nzValue="middle">Middle</label>
              <label nz-radio-button nzValue="small">Small</label>
            </nz-radio-group>
          </nz-form-control>
        </nz-form-item>
        <nz-form-item>
          <nz-form-label><label>Pagination Position</label></nz-form-label>
          <nz-form-control>
            <nz-radio-group [(ngModel)]="position" name="position">
              <label nz-radio-button nzValue="top">Top</label>
              <label nz-radio-button nzValue="bottom">Bottom</label>
              <label nz-radio-button nzValue="both">Both</label>
            </nz-radio-group>
          </nz-form-control>
        </nz-form-item>
      </form>
    </div>
    <nz-table
      #dynamicTable
      [nzScroll]="fixHeader ? { y: '240px' } : null"
      [nzData]="listOfData"
      [nzBordered]="bordered"
      [nzSimple]="simple"
      [nzLoading]="loading"
      [nzPaginationPosition]="position"
      [nzShowSizeChanger]="sizeChanger"
      [nzFrontPagination]="pagination"
      [nzShowPagination]="pagination"
      [nzFooter]="footer ? 'Here is Footer' : null"
      [nzTitle]="title ? 'Here is Title' : null"
      [nzSize]="size"
      (nzCurrentPageDataChange)="currentPageDataChange($event)"
    >
      <thead>
        <tr *ngIf="header">
          <th nzWidth="50px" nzShowExpand *ngIf="expandable"></th>
          <th
            nzWidth="62px"
            nzShowCheckbox
            *ngIf="checkbox"
            [(nzChecked)]="allChecked"
            [nzIndeterminate]="indeterminate"
            (nzCheckedChange)="checkAll($event)"
          ></th>
          <th nzWidth="150px">Name</th>
          <th nzWidth="70px">Age</th>
          <th>Address</th>
          <th nzWidth="260px">Action</th>
        </tr>
      </thead>
      <tbody>
        <ng-template ngFor let-data [ngForOf]="dynamicTable.data">
          <tr>
            <td nzShowExpand *ngIf="expandable" [(nzExpand)]="data.expand"></td>
            <td nzShowCheckbox *ngIf="checkbox" [(nzChecked)]="data.checked" (nzCheckedChange)="refreshStatus()"></td>
            <td>{{ data.name }}</td>
            <td>{{ data.age }}</td>
            <td>{{ data.address }}</td>
            <td>
              <a href="#">Action 一 {{ data.name }}</a>
              <nz-divider nzType="vertical"></nz-divider>
              <a href="#">Delete</a>
            </td>
          </tr>
          <tr [nzExpand]="data.expand && expandable">
            <td></td>
            <td [attr.colspan]="checkbox ? 5 : 4">{{ data.description }}</td>
          </tr>
        </ng-template>
      </tbody>
    </nz-table>
  `,
  styles: [
    `
      .components-table-demo-control-bar {
        margin-bottom: 12px;
      }

      .nz-form-item {
        margin-right: 16px;
        margin-bottom: 8px;
      }
    `
  ]
})
export class NzDemoTableDynamicSettingsComponent implements OnInit {
  listOfData: ItemData[] = [];
  displayData: ItemData[] = [];
  bordered = false;
  loading = false;
  sizeChanger = false;
  pagination = true;
  header = true;
  title = true;
  footer = true;
  fixHeader = false;
  size = 'small';
  expandable = true;
  checkbox = true;
  allChecked = false;
  indeterminate = false;
  simple = false;
  noResult = false;
  position = 'bottom';

  currentPageDataChange($event: ItemData[]): void {
    this.displayData = $event;
    this.refreshStatus();
  }

  refreshStatus(): void {
    const validData = this.displayData.filter(value => !value.disabled);
    const allChecked = validData.length > 0 && validData.every(value => value.checked === true);
    const allUnChecked = validData.every(value => !value.checked);
    this.allChecked = allChecked;
    this.indeterminate = !allChecked && !allUnChecked;
  }

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

  ngOnInit(): void {
    for (let i = 1; i <= 100; i++) {
      this.listOfData.push({
        name: 'John Brown',
        age: `${i}2`,
        address: `New York No. ${i} Lake Park`,
        description: `My name is John Brown, I am ${i}2 years old, living in New York No. ${i} Lake Park.`,
        checked: false,
        expand: false
      });
    }
  }

  noResultChange(status: boolean): void {
    this.listOfData = [];
    if (!status) {
      this.ngOnInit();
    }
  }
}

API#

nz-table#

参数说明类型默认值全局配置
[nzData]数据数组any[]-
[nzFrontPagination]是否在前端对数据进行分页,如果在服务器分页数据或者需要在前端显示全部数据时传入 falsebooleantrue
[nzTotal]当前总数据,在服务器渲染时需要传入number-
[nzPageIndex]当前页码,可双向绑定number-
[nzPageSize]每页展示多少数据,可双向绑定number-
[nzShowPagination]是否显示分页器booleantrue
[nzPaginationPosition]指定分页显示的位置'top' | 'bottom' | 'both'bottom
[nzBordered]是否展示外边框和列边框booleanfalse
[nzWidthConfig]表头分组时指定每列宽度,与 thnzWidth 不可混用string[][]
[nzSize]正常或迷你类型'middle' | 'small' | 'default''default'
[nzLoading]页面是否加载中booleanfalse
[nzLoadingIndicator]加载指示符TemplateRef<void>-
[nzLoadingDelay]延迟显示加载效果的时间(防止闪烁)number0
[nzScroll]横向或纵向支持滚动,也可用于指定滚动区域的宽高度:{ x: "300px", y: "300px" }object-
[nzTitle]表格标题string | TemplateRef<void>-
[nzFooter]表格尾部string | TemplateRef<void>-
[nzNoResult]无数据时显示内容string | TemplateRef<void>-
[nzPageSizeOptions]页数选择器可选值number[][ 10, 20, 30, 40, 50 ]
[nzShowQuickJumper]是否可以快速跳转至某页booleanfalse
[nzShowSizeChanger]是否可以改变 nzPageSizebooleanfalse
[nzShowTotal]用于显示数据总量和当前数据范围,用法参照 Pagination 组件TemplateRef<{ $implicit: number, range: [ number, number ] }>-
[nzItemRender]用于自定义页码的结构,用法参照 Pagination 组件TemplateRef<{ $implicit: 'page' | 'prev' | 'next', page: number }>-
[nzHideOnSinglePage]只有一页时是否隐藏分页器booleanfalse
[nzSimple]当添加该属性时,显示为简单分页boolean-
[nzVirtualScroll]是否启用虚拟滚动模式,与 [nzScroll] 配合使用booleanfalse
[nzVirtualItemSize]虚拟滚动时每一列的高度,与 cdk itemSize 相同number0
[nzVirtualMaxBufferPx]缓冲区最大像素高度,与 cdk maxBufferPx 相同number200
[nzVirtualMinBufferPx]缓冲区最小像素高度,低于该值时将加载新结构,与 cdk minBufferPx 相同number100
[nzVirtualForTrackBy]虚拟滚动数据 TrackByFunction 函数TrackByFunction<T>-
(nzPageIndexChange)当前页码改变时的回调函数EventEmitter<number>-
(nzPageSizeChange)页数改变时的回调函数EventEmitter<number>-
(nzCurrentPageDataChange)当前页面展示数据改变的回调函数EventEmitter<any[]>-

th#

勾选属性

参数说明类型默认值
[nzShowCheckbox]是否添加checkboxboolean-
[nzDisabled]checkbox 是否禁用boolean-
[nzIndeterminate]checkbox indeterminate 状态boolean-
[nzChecked]checkbox 是否被选中,可双向绑定boolean-
(nzCheckedChange)选中的回调EventEmitter<boolean>-

下拉选择属性

参数说明类型默认值
[nzShowRowSelection]是否显示下拉选择boolean-
[nzSelections]下拉选择的内容 text 及回调函数 onSelectArray<{ text: string, onSelect: any }>-

排序属性

参数说明类型默认值
[nzShowSort]是否显示排序boolean-
[nzSortKey]排序key,非受控模式使用,与 theadnzSortChange 配合使用string-
[nzSort]当前排序状态,受控模式使用,可双向绑定'descend' | 'ascend' | nullnull
(nzSortChange)排序状态改变回调,受控模式使用EventEmitter<'descend' | 'ascend' | null>-

过滤属性

参数说明类型默认值
[nzShowFilter]是否显示过滤boolean-
[nzFilters]过滤器内容, 显示数据 text,回调函数传出 value,设置 byDefault 以默认应用过滤规则Array<{ text: string; value: any; byDefault?: boolean }>-
[nzFilterMultiple]是否为多选过滤器booleantrue
(nzFilterChange)过滤器内容选择的 value 数据回调EventEmitter<any[] | any>-

样式属性

参数说明类型默认值
[nzWidth]指定该列宽度,表头未分组时可用string-
[nzLeft]左侧距离,用于固定左侧列string-
[nzRight]右侧距离,用于固定右侧列string-
[nzAlign]设置列内容的对齐方式'left' | 'right' | 'center'-

其他

参数说明类型默认值
[nzExpand]当前列是否包含展开按钮boolean-

td#

勾选属性

参数说明类型默认值
[nzShowCheckbox]是否添加checkboxboolean-
[nzDisabled]checkbox 是否禁用boolean-
[nzIndeterminate]checkbox indeterminate 状态boolean-
[nzChecked]checkbox 是否被选中,可双向绑定boolean-
(nzCheckedChange)选中的回调EventEmitter<boolean>-

展开属性

参数说明类型默认值
[nzShowExpand]是否显示展开按钮boolean-
[nzExpand]当前展开按钮状态,可双向绑定boolean-
(nzExpandChange)当前展开按钮状态改变回调函数EventEmitter<boolean>-

样式属性

参数说明类型默认值
[nzLeft]左侧距离,用于固定左侧列string-
[nzRight]右侧距离,用于固定右侧列string-
[nzAlign]设置列内容的对齐方式'left' | 'right' | 'center'-
[nzBreakWord]是否折行显示booleanfalse

其他

参数说明类型默认值
[nzIndentSize]展示树形数据时,每层缩进的宽度,以 px 为单位number-

thead#

参数说明类型默认值
[nzSingleSort]是否单列排序模式,非受控排序下使用booleanfalse
(nzSortChange)排序改变时的回调函数,需要与 th 上的 nzSortKey 同时使用,非受控排序下使用EventEmitter<{ nzSortKey: string, value: 'descend' | 'ascend' | null }>-

tr#

参数说明类型默认值
[nzExpand]当前列是否展开,与 td 上的 nzExpand 属性配合使用boolean-

[nz-virtual-scroll]#

虚拟滚动时配合 ng-template 使用, 格式为: TemplateRef<{ $implicit: any, index: number }>.

注意#

按照 Angular 的设计,当需要对 nzData 中的数据进行增删时需要使用以下操作,使用 push 或者 splice 修改 nzData 的数据不会生效

// 增加数据
this.dataSet = [ ...this.dataSet, {
  key    : `${this.i}`,
  name   : `Edward King ${this.i}`,
  age    : '32',
  address: `London, Park Lane no. ${this.i}`
}];
// 删除数据
this.dataSet = this.dataSet.filter(d => d.key !== i);