表格
IMPORT MODULE

st 并不是在创造另一个表格组件,而是在 nz-table 基础上以可配置形式渲染表格,在中后台里这种方式可以满足绝大多数场景,但又可以更易地管理表格渲染动作。

关于数据源

data 支持三种不同格式数据源,整体分为:URL和静态数据两类;但可以透过参数的配置达到不同的效果,同时有非常多参数可通过 AlainSTConfig 重置默认值,使整个 st 组件模板达到极简。

URL

指的是通过一个 URL 字符串来获取数据。

  • 通过 req.paramsreq.method 等参数解决请求数据格式问题

  • 通过 res.reName 重置数据 key 而无须担心后端数据格式是否满足 st 需求

  • 通过 res.process 可以对表格渲染前对数据进一步优化

  • 通过 page.zeroIndexed 可以调整 http 请求时 pi 参数是否遵循 0 基索引,默认情况下为 1 基索引

  • 若返回体的值是数组类型,则强制不分页

  • 使用 _HttpClient 发起请求,因此满足 AlainThemeConfig 的配置也适用

静态数据

指的是通过指定值为 STData[]Observable<STData[]>,二者都遵循以下规则:

  • page.front 前端分页,默认:true

    • truest 根据 data 长度受控分页,包括:排序、过滤等

    • false 由用户通过 totaldata 参数受控分页,并维护 (change) 当分页变更时重新加载数据

  • page.show 是否显示分页器;当未指定时若 ps>total 情况下自动不显示

常见问题

Cannot read property 'text' of undefined

若组件已经加载完毕,此时如果再次改变 columns 时可能会出现该错误,这是因为 st 每次只会根据 columns 对数据处理,当列定义发生改变后可能会因为列定义与现有数据无法配对,可能需要使用 this.st.resetColumns({ columns: [], emitReload: true }) 来更新列定义并重新加载数据。

某列显示INVALID DATA

当在解析列数据时抛出异常时,会强制显示 INVALID DATA,例如当某指定 type: 'number' 时,而实际获得值为非有效数字型时就会抛出异常。

代码演示

编号头像邮箱电话佣金(单位:元)注册时间
编号1头像邮箱aaa8@qq.com电话phone-21853佣金(单位:元)1,530,942注册时间2022-08-27 11:18
编号2头像邮箱aaa1@qq.com电话phone-37592佣金(单位:元)4,846,601注册时间2022-08-27 11:18
编号3头像邮箱aaa6@qq.com电话phone-24453佣金(单位:元)2,604,585注册时间2022-08-27 11:18
基本

快速生成表格;利用 res 可以适配后端数据格式。

expand codeexpand code
import { Component, ViewChild } from '@angular/core';
import { STColumn, STComponent } from '@delon/abc/st';

@Component({
  selector: 'components-st-basic',
  template: `
    <button nz-button nzType="primary" (click)="setRow()">setRow Method</button>
    <st #st [widthMode]="{ type: 'strict' }" [data]="url" [req]="{ params: params }" [columns]="columns"></st>
  `,
})
export class ComponentsStBasicComponent {
  url = `/users?total=2&field=list`;
  params = { a: 1, b: 2 };
  @ViewChild('st', { static: false }) private st!: STComponent;
  columns: STColumn[] = [
    { title: '编号', index: 'id', width: 80 },
    { title: '头像', type: 'img', width: 60, index: 'picture.thumbnail' },
    { title: '邮箱', index: 'email', width: 80 },
    { title: '电话', index: 'phone' },
    { title: { text: '佣金', optional: '(单位:元)', optionalHelp: '计算公式=订单金额 * 0.6%' }, index: 'price', type: 'currency' },
    { title: '注册时间', type: 'date', index: 'registered' },
  ];

  setRow(): void {
    this.st.setRow(0, { price: 100000000 });
  }
}
姓名年龄状态Date
编号姓名name 1年龄21状态ErrorDate2022-08-27 11:18
编号姓名name 2年龄27状态ErrorDate2022-08-27 11:18
编号姓名name 3年龄30状态DefaultDate2022-08-27 11:18
自定义数据

data 属性支持 STData[]Observable 数据类型。

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

import { STChange, STColumn, STData } from '@delon/abc/st';
import { dateTimePickerUtil } from '@delon/util/date-time';

@Component({
  selector: 'components-st-custom-data',
  template: `
    <div class="mb-md">
      <button (click)="st.clear()" nz-button>Clear Data</button>
      <button (click)="st.reload()" nz-button>Reload Data</button>
      <button (click)="st.clearStatus(); st.reload()" nz-button>Clear Status</button>
      <button (click)="st.setRow(0, { className: 'text-success' })" nz-button>Update Row ClassName</button>
    </div>
    <st #st [data]="users" [columns]="columns" (change)="change($event)"></st>
  `
})
export class ComponentsStCustomDataComponent implements OnInit {
  users: STData[] = [];
  columns: STColumn[] = [
    {
      title: '编号',
      index: 'id',
      type: 'checkbox',
      selections: [
        {
          text: '小于25岁',
          select: data => data.forEach(item => (item.checked = item.age < 25))
        },
        {
          text: '大于25岁',
          select: data => data.forEach(item => (item.checked = item.age >= 25))
        }
      ]
    },
    {
      title: '姓名',
      index: 'name',
      sort: {
        compare: (a, b) => a.name.length - b.name.length
      },
      filter: {
        type: 'keyword',
        placeholder: '输入后按回车搜索',
        fn: (filter, record) => !filter.value || record.name.indexOf(filter.value) !== -1
      }
    },
    {
      title: '年龄',
      index: 'age',
      sort: {
        compare: (a, b) => a.age - b.age
      },
      filter: {
        type: 'number',
        placeholder: '范围 10 ~ 100 之间',
        number: {
          min: 10,
          max: 100
        },
        fn: (filter, record) => (filter.value != null ? record.age >= +filter.value : true)
      }
    },
    {
      title: '状态',
      type: 'badge',
      index: 'status',
      badge: {
        1: { text: 'Success', color: 'success' },
        2: { text: 'Error', color: 'error' },
        3: { text: 'Processing', color: 'processing' },
        4: { text: 'Default', color: 'default' },
        5: { text: 'Warning', color: 'warning' }
      },
      filter: {
        menus: [
          { text: 'Success', value: 1 },
          { text: 'Error', value: 2 }
        ],
        fn: (filter, record) => record.age >= filter.value[0] && record.age <= filter.value[1],
        multiple: true
      }
    },
    {
      title: 'Date',
      index: 'created',
      type: 'date',
      filter: {
        type: 'date',
        date: {
          mode: 'date',
          showToday: false,
          disabledDate: dateTimePickerUtil.disabledAfterDate()
        },
        fn: () => true
      }
    }
  ];

  ngOnInit(): void {
    const data = Array(100)
      .fill({})
      .map((_, idx) => ({
        id: idx + 1,
        name: `name ${idx + 1}`,
        age: Math.ceil(Math.random() * 10) + 20,
        status: Math.floor(Math.random() * 5) + 1,
        created: new Date()
      }));
    of(data)
      .pipe(delay(500))
      .subscribe(res => (this.users = res));
  }

  change(e: STChange): void {
    console.log(e);
  }
}
行号姓名年龄HTMLTexttagbadgeEnumyn
行号1姓名name 1年龄22HTML1 OtherText<strong>1</strong> Othertag进行中badge进行中Enumyn
行号2姓名name 2年龄10HTML2 OtherText<strong>2</strong> Othertag默认badge成功Enumyn
行号3姓名name 3年龄50HTML3 OtherText<strong>3</strong> Othertag错误badge错误Enumyn
列类型

支持十种不同列类型:行号、多选、单选、徽标、标签、图片、数字、货币、日期、布尔徽章、枚举。也可以使用自定义列完成更复杂渲染。

expand codeexpand code
import { Component } from '@angular/core';
import { STColumn, STColumnBadge, STColumnTag } from '@delon/abc/st';

const BADGE: STColumnBadge = {
  1: { text: '成功', color: 'success' },
  2: { text: '错误', color: 'error' },
  3: { text: '进行中', color: 'processing' },
  4: { text: '默认', color: 'default' },
  5: { text: '警告', color: 'warning' },
};
const TAG: STColumnTag = {
  1: { text: '成功', color: 'green' },
  2: { text: '错误', color: 'red' },
  3: { text: '进行中', color: 'blue' },
  4: { text: '默认', color: '' },
  5: { text: '警告', color: 'orange' },
};
const r = (min: number, max: number) => Math.floor(Math.random() * (max - min + 1) + min);

@Component({
  selector: 'components-st-type',
  template: `
    <button nz-button (click)="reload()">Reload</button>
    <st #st [data]="users" [columns]="columns" [page]="{ position: 'both' }"></st>
  `,
})
export class ComponentsStTypeComponent {
  users: any[] = [];
  columns: STColumn[] = [
    { title: '行号', type: 'no' },
    { title: '姓名', index: 'name' },
    { title: '年龄', index: 'age', type: 'number' },
    { title: 'HTML', index: 'html', safeType: 'safeHtml' },
    { title: 'Text', index: 'html', safeType: 'text' },
    { title: 'tag', index: 'tag', type: 'tag', tag: TAG },
    { title: 'badge', index: 'badge', type: 'badge', badge: BADGE },
    { title: 'Enum', index: 'enum', type: 'enum', enum: { 1: '壹', 2: '贰', 3: '叁' } },
    { title: 'yn', index: 'yn', type: 'yn' },
  ];

  reload(): void {
    this.users = Array(10)
      .fill({})
      .map((_, idx) => ({
        id: idx + 1,
        name: `name ${idx + 1}`,
        age: r(10, 50),
        tag: r(1, 5),
        badge: r(1, 5),
        enum: r(1, 3),
        yn: [true, false][r(1, 5) % 2],
        html: `<strong>${idx + 1}</strong> Other`,
      }));
  }

  constructor() {
    this.reload();
  }
}
头像邮箱电话注册时间
编号头像邮箱aaa6@qq.com电话phone-21416注册时间2022-08-27 11:18
编号头像邮箱aaa9@qq.com电话phone-35647注册时间2022-08-27 11:18
编号头像邮箱aaa5@qq.com电话phone-88199注册时间2022-08-27 11:18
可选择

利用 change 监听所选的数据。

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

import { STChange, STColumn, STData } from '@delon/abc/st';

@Component({
  selector: 'components-st-checkbox',
  template: ` <div class="mb-md">
      <button nz-button (click)="st.checkAll(true)">All</button>
      <button nz-button (click)="st.clearCheck()">Clean</button>
    </div>
    <st
      #st
      [data]="url"
      [columns]="columns"
      [req]="{ params: params }"
      [res]="{ process: dataProcess }"
      (change)="change($event)"
    ></st>`
})
export class ComponentsStCheckboxComponent {
  url = `/users?total=100`;
  params = { a: 1, b: 2 };
  columns: STColumn[] = [
    { title: '编号', index: 'id.value', type: 'checkbox' },
    { title: '头像', type: 'img', width: 60, index: 'picture.thumbnail' },
    { title: '邮箱', index: 'email' },
    { title: '电话', index: 'phone' },
    { title: '注册时间', type: 'date', index: 'registered' }
  ];
  change(e: STChange): void {
    console.log('change', e);
  }
  dataProcess(data: STData[]): STData[] {
    return data.map((i, index) => {
      i.disabled = index === 0;
      if (index === 1) i.checked = true;
      return i;
    });
  }
}
编号头像邮箱电话注册时间
编号头像邮箱aaa4@qq.com电话phone-79385注册时间2022-08-27 11:18
编号头像邮箱aaa1@qq.com电话phone-62442注册时间2022-08-27 11:18
编号头像邮箱aaa10@qq.com电话phone-13416注册时间2022-08-27 11:18
单选框

利用 change 监听所选的数据。

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

import { STChange, STColumn, STData } from '@delon/abc/st';

@Component({
  selector: 'components-st-radio',
  template: ` <div class="mb-md">
      <button nz-button (click)="st.setRow(1, { checked: true })">Radio second</button>
      <button nz-button (click)="st.clearRadio()">Clean</button>
    </div>
    <st
      #st
      [data]="url"
      [columns]="columns"
      [req]="{ params: params }"
      [res]="{ process: dataChange }"
      (change)="change($event)"
    ></st>`
})
export class ComponentsStRadioComponent {
  url = `/users?total=300`;
  params = { a: 1, b: 2 };
  columns: STColumn[] = [
    { title: '编号', index: 'id', type: 'radio', width: 70 },
    { title: '头像', type: 'img', width: 60, index: 'picture.thumbnail' },
    { title: '邮箱', index: 'email' },
    { title: '电话', index: 'phone' },
    { title: '注册时间', type: 'date', index: 'registered' }
  ];

  change(ret: STChange): void {
    console.log('change', ret);
  }

  dataChange(data: STData[]): STData[] {
    return data.map((i, index) => {
      i.disabled = index === 0;
      i.hidden = index === 1;
      return i;
    });
  }
}
编号邮箱电话注册时间
编号1邮箱aaa3@qq.com电话phone-26480注册时间2022-08-27 11:18
编号2邮箱aaa2@qq.com电话phone-5891注册时间2022-08-27 11:18
编号3邮箱aaa10@qq.com电话phone-64157注册时间2022-08-27 11:18
右键菜单

利用 contextmenu 实现点击整个表格右键菜单。

expand codeexpand code
import { Component } from '@angular/core';
import { STColumn, STContextmenuFn, STContextmenuItem, STContextmenuOptions } from '@delon/abc/st';
import { NzMessageService } from 'ng-zorro-antd/message';

@Component({
  selector: 'components-st-contextmenu',
  template: `
    <st
      #st
      [widthMode]="{ type: 'strict' }"
      [data]="url"
      [req]="{ params: params }"
      [columns]="columns"
      [contextmenu]="handleContextmenu"
    ></st>
  `,
})
export class ComponentsStContextmenuComponent {
  url = `/users?total=2&field=list`;
  params = { a: 1, b: 2 };
  columns: STColumn[] = [
    { title: '编号', index: 'id', width: 80 },
    { title: '邮箱', index: 'email', width: 80 },
    { title: '电话', index: 'phone' },
    { title: '注册时间', type: 'date', index: 'registered' },
  ];

  constructor(private msg: NzMessageService) {}

  private show(options: STContextmenuOptions, item: STContextmenuItem): void {
    if (options.type === 'head') {
      this.msg.info(`点击标题,下标为:${options.colIndex},当前按钮为:${item.text}`);
    } else {
      this.msg.info(`点击单元格,行下标为:${options.rowIndex},列下标为:${options.colIndex},当前按钮为:${item.text}`);
    }
  }

  handleContextmenu: STContextmenuFn = (options): STContextmenuItem[] => {
    if (options.type === 'head') {
      return [
        {
          text: 'Click me',
          fn: item => this.show(options, item),
        },
      ];
    }
    return [
      {
        text: 'Edit',
        fn: item => this.show(options, item),
      },
      {
        text: 'View',
        fn: item => this.show(options, item),
      },
      {
        text: 'Next',
        children: [
          {
            text: 'Nothing',
            fn: item => this.show(options, item),
          },
          {
            text: 'asdf',
            fn: item => this.show(options, item),
          },
        ],
      },
    ];
  };
}
编号姓名年龄启用OP
编号1姓名name 1年龄24启用YOPEdit
编号2姓名name 2年龄30启用NOPEdit
编号3姓名name 3年龄28启用YOPEdit
可编辑行

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

expand codeexpand code
import { Component, ViewChild } from '@angular/core';
import { STColumn, STComponent, STData } from '@delon/abc/st';
import { NzMessageService } from 'ng-zorro-antd/message';

@Component({
  selector: 'components-st-edit-row',
  template: `
    <st #st [data]="users" [columns]="columns">
      <ng-template st-row="nameTpl" let-item let-index="index">
        <input *ngIf="item.edit" nz-input [ngModel]="item.name" (ngModelChange)="st.setRow(index, { name: $event })" />
        <ng-container *ngIf="!item.edit">{{ item.name }}</ng-container>
      </ng-template>
      <ng-template st-row="ageTpl" let-item let-index="index">
        <nz-input-number *ngIf="item.edit" [ngModel]="item.age" (ngModelChange)="st.setRow(index, { age: $event })"></nz-input-number>
        <ng-container *ngIf="!item.edit">{{ item.age }}</ng-container>
      </ng-template>
      <ng-template st-row="enabledTpl" let-item let-index="index">
        <nz-switch *ngIf="item.edit" [ngModel]="item.enabled" (ngModelChange)="st.setRow(index, { enabled: $event })"></nz-switch>
        <ng-container *ngIf="!item.edit">{{ item.enabled ? 'Y' : 'N' }}</ng-container>
      </ng-template>
    </st>
  `,
})
export class ComponentsStEditRowComponent {
  @ViewChild('st') private st!: STComponent;
  users: STData[] = Array(10)
    .fill({})
    .map((_, idx) => {
      return {
        id: idx + 1,
        name: `name ${idx + 1}`,
        age: Math.ceil(Math.random() * 10) + 20,
        enabled: idx % 2 === 0,
      };
    });
  columns: STColumn[] = [
    { title: '编号', index: 'id' },
    { title: '姓名', index: 'name', render: 'nameTpl' },
    { title: '年龄', index: 'age', render: 'ageTpl' },
    { title: '启用', index: 'enabled', render: 'enabledTpl' },
    {
      title: 'OP',
      buttons: [
        {
          text: `Edit`,
          iif: i => !i.edit,
          click: i => this.updateEdit(i, true),
        },
        {
          text: `Save`,
          iif: i => i.edit,
          click: i => {
            this.submit(i);
          },
        },
        {
          text: `Cancel`,
          iif: i => i.edit,
          click: i => this.updateEdit(i, false),
        },
      ],
    },
  ];

  constructor(private msg: NzMessageService) {}

  private submit(i: STData): void {
    this.msg.success(JSON.stringify(this.st.pureItem(i)));
    this.updateEdit(i, false);
  }

  private updateEdit(i: STData, edit: boolean): void {
    this.st.setRow(i, { edit }, { refreshSchema: true });
  }
}
编号头像邮箱电话注册时间
编号1头像邮箱aaa8@qq.com电话phone-57710注册时间2022-08-27 11:18
编号2头像邮箱aaa9@qq.com电话phone-33482注册时间2022-08-27 11:18
编号3头像邮箱aaa9@qq.com电话phone-10655注册时间2022-08-27 11:18
搜索表单

配合 load() & reset() 实现搜索表单。

expand codeexpand code
import { Component } from '@angular/core';
import { STColumn } from '@delon/abc/st';

@Component({
  selector: 'components-st-form',
  template: `
    <div class="mb-md">
      <input nz-input [(ngModel)]="params.name" name="name" nzPlaceHolder="请输入姓名" style="width: 100px;" class="mr-sm" />
      <button nz-button (click)="st.load(1)" [nzType]="'primary'">搜索</button>
      <button nz-button (click)="params = {}; st.reset()">重置</button>
    </div>
    <st #st [data]="url" [req]="{ params: params }" [columns]="columns"></st>
  `,
})
export class ComponentsStFormComponent {
  url = `/users?total=100`;
  params: { name?: string } = { name: 'asdf' };
  columns: STColumn[] = [
    { title: '编号', index: 'id', default: '-' },
    { title: '头像', type: 'img', width: 60, index: 'picture.thumbnail' },
    { title: '邮箱', index: 'email' },
    { title: '电话', index: 'phone' },
    { title: '注册时间', type: 'date', index: 'registered' },
  ];
}
编号邮箱电话
编号1邮箱aaa1@qq.com电话phone-90201
编号2邮箱aaa6@qq.com电话phone-74523
编号3邮箱aaa10@qq.com电话phone-99840
行操作

利用 addRowremoveRowsetRow 方法对行的操作。

打开控制面板了解打印明细。

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

import { STChange, STClickRowClassNameType, STColumn } from '@delon/abc/st';

@Component({
  selector: 'components-st-row-op',
  template: ` <button nz-button (click)="st.addRow({ id: 1000, email: 'add@email.com', phone: '123' })"> addRow</button>
    <button nz-button (click)="st.removeRow(0)"> removeRow index: 0 </button>
    <button nz-button (click)="st.setRow(0, { className: 'text-success' })"> Via setRow method </button>
    <st
      #st
      [data]="url"
      [req]="{ params: params }"
      [columns]="columns"
      (change)="_click($event)"
      [clickRowClassName]="clickRowClassName"
    ></st>`
})
export class ComponentsStRowOpComponent {
  url = `/users?results=3`;
  params = { a: 1, b: 2 };
  clickRowClassName: STClickRowClassNameType = { exclusive: true, fn: () => 'text-error' };
  columns: STColumn[] = [
    { title: '编号', index: 'id' },
    { title: '邮箱', index: 'email' },
    { title: '电话', index: 'phone' }
  ];

  _click(e: STChange): void {
    console.log('click', e);
  }
}
编号头像姓名国家性别注册时间
编号1头像姓名1: last-6 first-12国家CH性别male注册时间2022-08-27 11:18
编号2头像姓名2: last-2 first-12国家US性别female注册时间2022-08-27 11:18
编号3头像姓名3: last-6 first-12国家DE性别male注册时间2022-08-27 11:18
后端筛选和排序

利用 multiSort 支持多字段排序。

expand codeexpand code
import { Component } from '@angular/core';
import { STColumn, STData } from '@delon/abc/st';

interface UserData extends STData {
  name: {
    last: string;
    first: string;
  }
}

@Component({
  selector: 'components-st-sort',
  template: `
    <button nz-button (click)="st.reset()">重置</button>
    <st #st [data]="url" [req]="{ params: params }" [columns]="columns" multiSort></st>
  `,
})
export class ComponentsStSortComponent {
  url = `/users?total=200`;
  params = { a: 1, b: 2 };
  columns: STColumn<UserData>[] = [
    { title: '编号', index: 'id' },
    { title: '头像', type: 'img', width: 60, index: 'picture.thumbnail' },
    {
      title: '姓名',
      index: 'name.last',
      format: (item, _col, index) => `${index + 1}: ${item.name.last} ${item.name.first}`,
      sort: true,
    },
    {
      title: '国家',
      index: 'nat',
      filter: {
        menus: [
          { text: '中国', value: 'CH' },
          { text: '美国', value: 'US' },
          { text: '德国', value: 'DE' },
        ],
      },
      sort: true,
    },
    {
      title: '性别',
      index: 'gender',
      filter: {
        menus: [
          { text: 'male', value: 'male' },
          { text: 'female', value: 'female' },
        ],
        multiple: false,
      },
      sort: true,
    },
    { title: '注册时间', type: 'date', index: 'registered' },
  ];
}
编号姓名年龄
编号1姓名name 1年龄25Button
编号2姓名name 2年龄21Button
编号3姓名name 3年龄26Button
可展开

使用 #expand 模板实现可展开,允许接收 itemindexcolumn 三个值。附加可实现:嵌套子表格。

expand codeexpand code
import { Component } from '@angular/core';
import { STColumn, STData } from '@delon/abc/st';

@Component({
  selector: 'components-st-expand',
  template: `
    <st [data]="users" [columns]="columns" [expand]="expand" expandRowByClick expandAccordion>
      <ng-template #expand let-item let-index="index" let-column="column">
        {{ item.description }}
      </ng-template>
    </st>
  `,
})
export class ComponentsStExpandComponent {
  users: STData[] = Array(10)
    .fill({})
    .map((_, idx) => ({
      id: idx + 1,
      name: `name ${idx + 1}`,
      age: Math.ceil(Math.random() * 10) + 20,
      // 是否显示展开按钮
      showExpand: idx !== 0,
      description: `${idx + 1}. My name is John Brown, I am 32 years old, living in New York No. 1 Lake Park.`,
    }));
  columns: STColumn[] = [
    { title: '编号', index: 'id' },
    { title: '姓名', index: 'name' },
    { title: '年龄', index: 'age' },
    {
      buttons: [
        {
          text: 'Button',
        },
      ],
    },
  ];
}
编号姓名年龄自定义
编号1姓名name 1年龄26自定义tooltip: 26-0
编号2姓名name 2年龄21自定义tooltip: 21-1
编号3姓名name 3年龄25自定义tooltip: 25-2
自定义列

创建一个带有 st-row="custom-name"ng-template,并在列描述 render: 'custom-name' 指定名称;模板允许接收 itemindexcolumn 三个值。

如果指定 type="title" 表示是对标题自定义列。附加可实现:表头分组。

expand codeexpand code
import { Component } from '@angular/core';
import { STColumn, STData } from '@delon/abc/st';

@Component({
  selector: 'components-st-render',
  template: `
    <div class="mb-md">
      <nz-checkbox-group
        [(ngModel)]="customColumns"
        name="customColumns"
        (ngModelChange)="st.resetColumns({ emitReload: true })"
      ></nz-checkbox-group>
    </div>
    <st #st [data]="users" [columns]="columns">
      <ng-template st-row="customTitle" type="title" let-c>
        {{ c.title.text }}
        <span nz-dropdown [nzDropdownMenu]="menuTpl" nzTrigger="click" [nzClickHide]="false" nzPlacement="bottomRight">
          <i nz-icon nzType="down"></i>
        </span>
        <nz-dropdown-menu #menuTpl="nzDropdownMenu">
          <div class="ant-table-filter-dropdown p-sm">
            <input type="text" nz-input placeholder="Search name" [(ngModel)]="searchValue" name="searchValue" class="width-sm mr-sm" />
            <button nz-button [nzType]="'primary'" (click)="st.load(2)">Search</button>
          </div>
        </nz-dropdown-menu>
      </ng-template>
      <ng-template st-row="custom" let-item let-index="index">
        <span nz-tooltip [nzTooltipTitle]="'年龄:' + item.age">tooltip: {{ item.age }}-{{ index }}</span>
      </ng-template>
    </st>
  `,
})
export class ComponentsStRenderComponent {
  searchValue?: string;
  users: STData[] = Array(10)
    .fill({})
    .map((_, idx) => {
      return {
        id: idx + 1,
        name: `name ${idx + 1}`,
        age: Math.ceil(Math.random() * 10) + 20,
      };
    });
  columns: STColumn[] = [
    { title: '编号', index: 'id' },
    { title: '姓名', index: 'name', iif: () => this.isChoose('name') },
    { title: '年龄', index: 'age', iif: () => this.isChoose('age') },
    {
      title: '自定义',
      renderTitle: 'customTitle',
      render: 'custom',
      iif: () => this.isChoose('custom'),
    },
  ];
  customColumns = [
    { label: '姓名', value: 'name', checked: true },
    { label: '年龄', value: 'age', checked: true },
    { label: '自定义', value: 'custom', checked: true },
  ];

  isChoose(key: string): boolean {
    return !!this.customColumns.find(w => w.value === key && w.checked);
  }
}
序号编号姓名年龄操作区
序号1编号1姓名name 1年龄25操作区EditDrawer更多
序号2编号2姓名name 2年龄27操作区EditDrawer更多
序号3编号3姓名name 3年龄26操作区EditDrawer更多
自定义按钮组

透过简单的配置产生一组日常按钮组(目标组件示例:DemoModalComponentDemoDrawerComponent)。

对话框由ModalHelper处理,抽屉由DrawerHelper处理。

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

import { DemoDrawerComponent, DemoModalComponent } from '@shared';

import { STChange, STColumn, STData } from '@delon/abc/st';
import { NzMessageService } from 'ng-zorro-antd/message';

@Component({
  selector: 'components-st-buttons',
  template: ` <st [data]="users" [columns]="columns" (change)="change($event)"></st> `
})
export class ComponentsStButtonsComponent {
  constructor(private message: NzMessageService) {}

  users: STData[] = Array(10)
    .fill({})
    .map((_, idx) => ({
      id: idx + 1,
      name: `name ${idx + 1}`,
      age: Math.ceil(Math.random() * 10) + 20
    }));
  columns: STColumn[] = [
    { title: '序号', type: 'no' },
    { title: '编号', index: 'id' },
    { title: '姓名', index: 'name' },
    { title: '年龄', index: 'age' },
    {
      title: '操作区',
      buttons: [
        {
          text: 'Edit',
          icon: 'edit',
          type: 'modal',
          modal: {
            component: DemoModalComponent
          },
          click: (_record, modal) => this.message.success(`重新加载页面,回传值:${JSON.stringify(modal)}`)
        },
        {
          text: 'Drawer',
          type: 'drawer',
          drawer: {
            title: '编辑',
            component: DemoDrawerComponent
          },
          click: (_record, modal) => this.message.success(`重新加载页面,回传值:${JSON.stringify(modal)}`)
        },
        {
          icon: 'check-circle',
          click: record => this.message.info(`check-${record.name}`),
          iif: record => record.id % 2 === 0,
          iifBehavior: 'disabled',
          tooltip: `Is disabled button`
        },
        {
          icon: 'delete',
          type: 'del',
          pop: {
            title: 'Yar you sure?',
            okType: 'danger',
            icon: 'star'
          },
          click: (record, _modal, comp) => {
            this.message.success(`成功删除【${record.name}】`);
            comp!.removeRow(record);
          },
          iif: record => record.id % 2 === 0
        },
        {
          text: '更多',
          children: [
            {
              text: record => (record.id === 1 ? `过期` : `正常`),
              click: record => this.message.error(`${record.id === 1 ? `过期` : `正常`}【${record.name}】`)
            },
            {
              text: `审核`,
              click: record => this.message.info(`check-${record.name}`),
              iif: record => record.id % 2 === 0,
              iifBehavior: 'disabled',
              tooltip: 'This is tooltip'
            },
            {
              type: 'divider'
            },
            {
              text: `重新开始`,
              icon: 'edit',
              click: record => this.message.success(`重新开始【${record.name}】`)
            }
          ]
        }
      ]
    }
  ];

  change(e: STChange): void {
    console.log(e);
  }
}
编号自定义头像邮箱
编号1自定义头像邮箱aaa7@qq.com
编号2自定义头像邮箱aaa10@qq.com
编号3自定义头像邮箱aaa1@qq.com
自定义小部件

类型为 widget 自定义小部件,例如点击头像处理。

expand codeexpand code
import { Component, ViewChild } from '@angular/core';
import { STColumn, STComponent } from '@delon/abc/st';

@Component({
  selector: 'components-st-widget',
  template: `
    <div class="mb-md">
      <button (click)="st.clear()" nz-button>Clear Data</button>
      <button (click)="st.reload()" nz-button>Reload Data</button>
      <button (click)="st.clearStatus(); st.reload()" nz-button>Clear Status</button>
      <button (click)="changeImg()" nz-button>Change Img Data</button>
    </div>
    <st #st [data]="url" [columns]="columns"></st>
  `,
})
export class ComponentsStWidgetComponent {
  url = `/users?total=100`;
  @ViewChild('st', { static: false }) private st!: STComponent;
  columns: STColumn[] = [
    { title: '编号', index: 'id', width: 80 },
    {
      title: '自定义头像',
      type: 'widget',
      widget: { type: 'img', params: ({ record }) => ({ img: record.picture.thumbnail }) },
      width: 150,
    },
    { title: '邮箱', index: 'email' },
  ];

  changeImg(): void {
    this.st.setRow(
      0,
      { picture: { thumbnail: 'https://ng-alain.com/assets/img/logo-color.svg' } },
      { refreshSchema: true, emitReload: false },
    );
  }
}
编号1编号2编号3编号4编号5编号6编号7编号8编号8编号8编号8编号8姓名10姓名11年龄12
编号11编号21编号31编号41编号51编号61编号71编号81编号81编号81编号81编号81姓名10name 1姓名11name 1年龄1228
编号12编号22编号32编号42编号52编号62编号72编号82编号82编号82编号82编号82姓名10name 2姓名11name 2年龄1229
编号13编号23编号33编号43编号53编号63编号73编号83编号83编号83编号83编号83姓名10name 3姓名11name 3年龄1222
固定列

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

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

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

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

expand codeexpand code
import { Component } from '@angular/core';
import { STColumn, STData } from '@delon/abc/st';

@Component({
  selector: 'components-st-fixed',
  template: ` <st [data]="users" [columns]="columns" [scroll]="{ x: '1300px' }"></st> `,
})
export class ComponentsStFixedComponent {
  users: STData[] = Array(10)
    .fill({})
    .map((_, idx) => {
      return {
        id: idx + 1,
        name: `name ${idx + 1}`,
        age: Math.ceil(Math.random() * 10) + 20,
      };
    });
  columns: STColumn[] = [
    { title: '编号1', index: 'id', fixed: 'left', width: 100 },
    { title: '编号2', index: 'id', fixed: 'left', width: 100 },
    { title: '编号3', index: 'id', fixed: 'left', width: 100 },
    { title: '编号4', index: 'id' },
    { title: '编号5', index: 'id' },
    { title: '编号6', index: 'id' },
    { title: '编号7', index: 'id' },
    { title: '编号8', index: 'id' },
    { title: '编号8', index: 'id' },
    { title: '编号8', index: 'id' },
    { title: '编号8', index: 'id' },
    { title: '编号8', index: 'id' },
    { title: '姓名10', index: 'name', fixed: 'right', width: 100 },
    { title: '姓名11', index: 'name', fixed: 'right', width: 100 },
    { title: '年龄12', index: 'age', fixed: 'right', width: 100 },
  ];
}
编号Other
头像邮箱姓名
firstlast
编号1头像邮箱aaa5@qq.comfirstfirst-20lastlast-5
编号2头像邮箱aaa1@qq.comfirstfirst-11lastlast-6
编号3头像邮箱aaa1@qq.comfirstfirst-18lastlast-9
表头分组

columns[n] 可以内嵌 children,以渲染分组表头。

expand codeexpand code
import { Component } from '@angular/core';
import { STColumn } from '@delon/abc/st';

@Component({
  selector: 'components-st-grouping-columns',
  template: ` <st #st [data]="url" [req]="{ params: params }" [columns]="columns" bordered size="middle"> </st>`,
})
export class ComponentsStGroupingColumnsComponent {
  url = `/users?total=2&field=list`;
  params = { a: 1, b: 2 };
  columns: STColumn[] = [
    { title: '编号', index: 'id', sort: true, width: 100 },
    {
      title: 'Other',
      children: [
        { title: '头像', type: 'img', index: 'picture.thumbnail', width: 60 },
        { title: '邮箱', index: 'email' },
        {
          title: '姓名',
          sort: true,
          children: [
            { title: 'first', index: 'name.first', sort: true },
            { title: 'last', index: 'name.last' },
          ],
        },
      ],
    },
  ];
}
The header
编号头像邮箱电话注册时间
编号1头像邮箱aaa7@qq.com电话phone-33040注册时间2022-08-27 11:18
编号2头像邮箱aaa4@qq.com电话phone-22677注册时间2022-08-27 11:18
编号3头像邮箱aaa10@qq.com电话phone-18477注册时间2022-08-27 11:18
The footer
响应式

小屏幕下将以响应模式堆叠显示,responsiveHideHeaderFooter 属性可以使大屏幕不显示头和尾,反之。

expand codeexpand code
import { Component } from '@angular/core';
import { STColumn } from '@delon/abc/st';

@Component({
  selector: 'components-st-responsive',
  template: ` <st
    [data]="url"
    [req]="{ params: params }"
    [columns]="columns"
    header="The header"
    footer="The footer"
    responsiveHideHeaderFooter
  >
  </st>`,
})
export class ComponentsStResponsiveComponent {
  url = `/users?total=100`;
  params = { a: 1, b: 2 };
  columns: STColumn[] = [
    { title: '编号', index: 'id' },
    { title: '头像', type: 'img', width: 60, index: 'picture.thumbnail' },
    { title: '邮箱', index: 'email' },
    { title: '电话', index: 'phone' },
    { title: '注册时间', type: 'date', index: 'registered' },
  ];
}
行号编号性别SumAverageMinMaxCustom
行号1编号1性别Sum4Average4Min4Max4Custom4
行号2编号2性别Sum79Average79Min79Max79Custom79
行号3编号3性别Sum43Average43Min43Max43Custom43
合计3 个2126424794
性别平均值42
统计

支持 countdistinctCountsumaveragemaxmin、自定义统计方法。

expand codeexpand code
import { Component } from '@angular/core';
import { STColumn, STData } from '@delon/abc/st';

@Component({
  selector: 'components-st-statistical',
  template: `
    <button nz-button (click)="data = []">Clean Data</button>
    <st #st [data]="data" [columns]="columns" [body]="bodyTpl">
      <ng-template #bodyTpl let-s>
        <ng-container *ngIf="st.count > 0">
          <tr>
            <td>合计</td>
            <td>{{ s.len.text }} 个</td>
            <td>{{ s.dc.text }}</td>
            <td class="text-right">{{ s.sum.text }}</td>
            <td class="text-right">{{ s.avg.text }}</td>
            <td class="text-right">{{ s.min.text }}</td>
            <td class="text-right">{{ s.max.text }}</td>
            <td class="text-right">{{ s.custom.text }}</td>
          </tr>
          <tr class="bg-grey-lighter">
            <td colspan="3">性别平均值</td>
            <td class="text-right">{{ s.sum.value / s.len.value | price }}</td>
            <td colspan="4"></td>
          </tr>
        </ng-container>
      </ng-template>
    </st>
  `,
})
export class ComponentsStStatisticalComponent {
  data: STData[] = Array(100)
    .fill({})
    .map((_, idx) => ({
      id: idx + 1,
      price: ~~(Math.random() * 100),
      age: ~~(Math.random() * 100) > 50 ? '女' : '男',
    }));
  columns: STColumn[] = [
    { title: '行号', type: 'no' },
    { title: '编号', index: 'id', statistical: 'count', key: 'len' },
    { title: '性别', index: 'age', statistical: 'distinctCount', key: 'dc' },
    { title: 'Sum', index: 'price', type: 'currency', statistical: 'sum', key: 'sum' },
    { title: 'Average', index: 'price', type: 'currency', statistical: 'average', key: 'avg' },
    { title: 'Min', index: 'price', type: 'currency', statistical: 'min', key: 'min' },
    { title: 'Max', index: 'price', type: 'currency', statistical: 'max', key: 'max' },
    {
      title: 'Custom',
      index: 'price',
      type: 'currency',
      statistical: { type: values => ({ value: values[0], text: `**${values[0]}` }), currency: false },
      key: 'custom',
    },
  ];
}
编号价格1价格2价格3价格4价格5价格6价格7价格8价格9价格10
虚拟滚动

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

expand codeexpand code
import { AfterViewInit, Component, OnDestroy, ViewChild } from '@angular/core';
import { STColumn, STComponent, STPage } from '@delon/abc/st';
import { Subject, takeUntil } from 'rxjs';

@Component({
  selector: 'components-st-virtual',
  template: `
    <button nz-button (click)="scrollToIndex(200)">Scroll To Index 200</button>
    <st #st [data]="data" [columns]="columns" [page]="page" virtualScroll [scroll]="{ x: '1300px', y: '240px' }"></st>
  `,
})
export class ComponentsStVirtualComponent implements AfterViewInit, OnDestroy {
  private destroy$ = new Subject<void>();
  @ViewChild('st', { static: false }) st!: STComponent;

  page: STPage = {
    front: false,
    show: false,
  };
  data: Array<{ id: number; price: number }> = Array(2000)
    .fill({})
    .map((_, idx) => ({
      id: idx + 1,
      price: ~~(Math.random() * 100),
    }));
  columns: STColumn[] = [
    { title: '编号', index: 'id', width: 100 },
    { title: '价格1', index: 'price', width: 100 },
    { title: '价格2', index: 'price', width: 100 },
    { title: '价格3', index: 'price', width: 100 },
    { title: '价格4', index: 'price', width: 100 },
    { title: '价格5', index: 'price', width: 100 },
    { title: '价格6', index: 'price', width: 100 },
    { title: '价格7', index: 'price', width: 100 },
    { title: '价格8', index: 'price', width: 100 },
    { title: '价格9', index: 'price', width: 100 },
    { title: '价格10', index: 'price', width: 100 },
  ];

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

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

  ngOnDestroy(): void {
    this.destroy$.next();
    this.destroy$.complete();
  }
}
编号头像邮箱电话数字货币注册时间
编号1头像邮箱e1@qq.com电话phone - 1数字14,145,299货币14,145,299注册时间2022-08-27 11:18
编号2头像邮箱e2@qq.com电话phone - 2数字15,427,080货币15,427,080注册时间2022-08-27 11:18
编号3头像邮箱e3@qq.com电话phone - 3数字16,507,061货币16,507,061注册时间2022-08-27 11:18
导出Excel

将表格数据保存为 Excel。

expand codeexpand code
import { Component, ViewChild } from '@angular/core';
import { STColumn, STComponent, STData } from '@delon/abc/st';

@Component({
  selector: 'components-st-export',
  template: `
    <button nz-button (click)="st.export()">Export</button>
    <button nz-button (click)="st.export(true)">Export Filtered Data</button>
    <button nz-button (click)="st.export(data, { filename: 'via-data.xlsx', sheetname: 'user' })">Export via data</button>
    <st #st [data]="data" [columns]="columns" class="mt-sm"></st>
  `,
})
export class ComponentsStExportComponent {
  @ViewChild('st', { static: false }) st!: STComponent;
  data: STData[] = Array(10000)
    .fill({})
    .map((_, index) => ({
      id: index + 1,
      picture: {
        thumbnail: `https://dummyimage.com/100x100&text=${Math.min(index + 1, 30)}`,
      },
      email: `e${index + 1}@qq.com`,
      phone: `phone - ${index + 1}`,
      price: Math.ceil(Math.random() * 10000000) + 10000000,
      registered: new Date(),
    }));
  columns: STColumn[] = [
    { title: '编号', index: 'id' },
    {
      title: '头像',
      type: 'img',
      width: 60,
      index: 'picture.thumbnail',
      exported: false,
    },
    { title: '邮箱', index: 'email' },
    { title: '电话', index: 'phone' },
    {
      title: '数字',
      index: 'price',
      type: 'number',
      sort: {
        compare: (a, b) => a.price - b.price,
      },
    },
    { title: '货币', index: 'price', type: 'currency' },
    { title: '注册时间', type: 'date', index: 'registered' },
  ];
}
编号头像邮箱电话佣金注册时间
编号1头像邮箱aaa7@qq.com电话phone-19711佣金5,366,898注册时间2022-08-27 11:18
编号2头像邮箱aaa3@qq.com电话phone-16015佣金8,530,548注册时间2022-08-27 11:18
编号3头像邮箱aaa6@qq.com电话phone-19685佣金7,107,559注册时间2022-08-27 11:18
调整尺寸

基于 nz-resizable 调整表头宽度。

  • 注意:不要忘记在 src/styles 下导入 nz-resizable Less 样式文件(@import 'ng-zorro-antd/resizable/style/entry.less';

  • 不支持多表头

expand codeexpand code
import { Component } from '@angular/core';
import { STChange, STColumn } from '@delon/abc/st';

@Component({
  selector: 'components-st-resizable',
  template: `
    <st
      [data]="url"
      [columns]="columns"
      [widthMode]="{ type: 'strict' }"
      resizable
      (change)="onChange($event)"
    ></st>
  `,
})
export class ComponentsStResizableComponent {
  url = `/users?total=2&field=list`;
  columns: STColumn[] = [
    { title: '编号', index: 'id', width: 80, resizable: false },
    { title: '头像', type: 'img', width: 60, index: 'picture.thumbnail' },
    { title: '邮箱', index: 'email', width: 150, resizable: { minWidth: 150 } },
    { title: '电话', index: 'phone' },
    { title: '佣金', index: 'price', type: 'currency' },
    { title: '注册时间', type: 'date', index: 'registered' },
  ];

  onChange({ type, resize }: STChange): void {
    if (type === 'resize') {
      console.log(resize?.width);
    }
  }
}

API

st

成员说明类型默认值全局配置
[columns]列描述STColumn[]--
[data]数据源string, STData[], Observable<STData[]>--
[req]请求体配置STReq-
[res]返回体配置STRes-
[pi]当前页码number1
[ps]每页数量,默认:10number10
[total]当前总数据,在服务器渲染时需要传入,默认:0number0-
[page]分页器配置STPage-
[noResult]无数据时显示内容string,TemplateRef<void>-
[bordered]是否显示边框booleanfalse
[size]table大小'small','middle','default''default'
[widthMode]设置表格宽度模式STWidthMode-
[rowClassName]表格行的类名(record: STData, index: number) => string-
[clickRowClassName]点击行切换类名string, STClickRowClassNameType-
[loading]页面是否加载中,当指定 null 由 st 受控boolean | nullnull-
[loadingIndicator]加载指示符TemplateRef<void>-
[loadingDelay]延迟显示加载效果的时间(防止闪烁)number0
[scroll]横向或纵向支持滚动,也可用于指定滚动区域的宽高度:{ x: "300px", y: "300px" }{ y?: string; x?: string }--
[virtualScroll]是否启用虚拟滚动模式,与 [nzScroll] 配合使用booleanfalse
[virtualItemSize]虚拟滚动时每一列的高度,与 cdk itemSize 相同number54
[virtualMaxBufferPx]缓冲区最大像素高度,与 cdk maxBufferPx 相同number200
[virtualMinBufferPx]缓冲区最小像素高度,低于该值时将加载新结构,与 cdk minBufferPx 相同number100
[virtualForTrackBy]虚拟滚动数据 TrackByFunction 函数TrackByFunction<T>-
[singleSort]单排序规则
若不指定,则返回:columnName=ascend|descend
若指定,则返回:sort=columnName.(ascend|descend)
STSingleSortnull
[multiSort]是否多排序,当 sort 多个相同值时自动合并,建议后端支持时使用boolean, STMultiSortfalse
[header]表格标题string,TemplateRef<void>--
[showHeader]是否显示列头行booleantrue-
[footer]表格底部string,TemplateRef<void>--
[bodyHeader]表格顶部额外内容,一般用于添加合计行TemplateRef<STStatisticalResults>--
[body]表格额外内容,一般用于添加合计行TemplateRef<STStatisticalResults>--
[widthConfig]表头分组时指定每列宽度,与 STColumn 的 width 不可混用string[]--
[expandRowByClick]通过点击行来展开子行booleanfalse
[expandAccordion]手风琴模式booleanfalse
[expand]当前列是否包含展开按钮,当数据源中包括 expand 表示展开状态TemplateRef<void>--
[responsive]是否开启响应式booleantrue
[responsiveHideHeaderFooter]是否在小屏幕下才显示顶部与底部booleanfalse
[resizable]当前表格所有列的调整表头配置项,不支持多表头STResizable, boolean--
(change)变化时回调,包括:pipscheckboxradiosortfilterclickdblClickexpand 变动EventEmitter<STChange>--
(error)异常时回调EventEmitter<STError>--

组件属性与方法

名称说明
[filteredData]获取过滤后所有数据
- 本地数据:包含排序、过滤后不分页数据
- 远程数据:不传递 pips 两个参数
[count]获取当前页的条目数
[list]获取当前页的数据列表
resetColumns(options?: STResetColumnsOption)重置列描述
load(pi = 1, extraParams?: any, options?: STLoadOptions)加载指定页
reload(extraParams?: any, options?: STLoadOptions)刷新当前页
reset(extraParams?: any, options?: STLoadOptions)重置且重新设置 pi1,包含单多选、排序、过滤状态(同默认状态一并清除)
addRow(data: STData | STData[], options?: { index?: number })添加行
removeRow(data: STData | STData[] | number)移除行
setRow(index: number | STData, item: STData, options?: { refreshSchema?: boolean; emitReload?: boolean })修改行数据,支持部分字段更新
pureItem(itemOrIndex: STData | number)返回纯净数据,st 内部会维护一组用于缓存的数据,这部分数据可能会影响后端
clear(cleanStatus = true)清空所有数据
clearStatus()清空所有状态(包含单多选、排序、过滤状态)
clearCheck()清除所有 checkbox
clearRadio()清除所有 radio
export(newData?: STData[] | true, opt?: STExportOptions)导出Excel,确保已经导入 XlsxModule

一些细节:

  • extraParams 若不传递表示保留原始值

  • STLoadOptions.merge 是否合并模式,即 extraParams 跟新值合并而非替代

  • STLoadOptions.toTop 是否跳转至顶部,若不指定由 page.toTop 来决定

使用方式

@Component({
  template: `
    <st #st></st>
    <button (click)="st.load()"></button>
    <button (click)="st.reset()">重置</button>
  `
})
class TestComponent {
  @ViewChild('st', { static: false }) comp: STComponent;
  // this.comp.load();
}

STReq

成员说明类型默认值全局配置
[type]分页类型,page 使用 pips 组合;skip 使用 skiplimit 组合page,skippage
[params]额外请求参数,默认自动附加 pips 至URLany--
[ignoreParamNull]是否忽略参数中 nullundefindBooleanfalse
[method]请求方法'POST','GET','HEAD','PUT','PATCH','DELETE''GET'
[body]请求体 body,当 method: POST 时有效any--
[headers]请求体 headersany-
[reName]重命名请求参数 pipsSTReqReNameType, ((result: any, options: { pi: number; ps: number; total: number }) => { total: number; list: T[] }){ pi: 'pi', ps: 'ps', skip: 'skip', limit: 'limit' }
[allInBody]是否将请求所有参数数据都放入 body 当中(url 地址本身参数除外),仅当 method: 'POST' 时有效booleanfalse
[lazyLoad]是否延迟加载数据,即渲染结束后不会主动发起请求booleanfalse
[process]请求前数据处理(requestOptions: STRequestOptions) => STRequestOptions-

STRes

成员说明类型默认值全局配置
[reName]重命名返回参数 totallist,支持 a.b.c 的嵌套写法{total:string;list:string}-
[process]数据预处理(data: STData[], rawData?: any) => STData[]-

STPage

成员说明类型默认值全局配置
[front]前端分页,当 dataany[]Observable<any[]> 有效booleantrue
[zeroIndexed]后端分页是否采用0基索引,只在data类型为string时有效booleanfalse
[position]指定分页显示的位置top,bottom,bothbottom
[placement]指定分页分页方向left,center,rightright
[show]是否显示分页器booleantrue
[showSize]是否显示分页器中改变页数booleanfalse
[pageSizes]分页器中每页显示条目数下拉框值number[][10, 20, 30, 40, 50]
[showQuickJumper]是否显示分页器中快速跳转booleanfalse
[total]是否显示总数据量,字符串表示自定义模板(支持三个变量名:total 表示数据总量、range[0]range[1] 表示当前数据范围;变量名统一使用双花括号包裹)boolean, stringfalse
[toTop]切换分页时返回顶部booleantrue
[toTopOffset]返回顶部偏移值number100
[itemRender]用于自定义页码的结构,用法参照 Pagination 组件TemplateRef<{ $implicit: 'page' \| 'prev' \| 'next', page: number }>-
[simple]当添加该属性时,显示为简单分页boolean-

STError

成员说明类型默认值
[type]异常类型,req 表示HTTP请求req-
[error]异常内容any-

STChange

成员说明类型默认值
[type]变更类型,包括:loadedpipscheckboxradiosortfilterfilterChangeclickdblClickexpandSTChangeType-
[pi]当前页码number-
[ps]每页数量number-
[total]数据总量number-
[loaded]loaded 参数STData[]-
[checkbox]checkbox 参数STData[]-
[radio]radio 参数STData-
[sort]排序参数STChangeSort-
[filter]过滤参数STColumn-
[click]行点击参数STChangeRowClick-
[dblClick]行双击参数STChangeRowClick-
[expand]expand 参数STData-

STChangeSort

成员说明类型默认值
[value]当前列排序状态ascend,descend-
[map]所有列排序状态{ [key: string]: string }-
[column]行描述STColumn-

STChangeRowClick

成员说明类型默认值
[e]当前行事件Event-
[item]当前行数据STData-
[index]当前行索引number-

STExportOptions

成员说明类型默认值
[sheetname]工作薄名称stringSheet1
[filename]保存的文件名stringexport.xslx
[callback]保存前的回调(wb: WorkBook) => void-

STSingleSort

成员说明类型默认值全局配置
[key]请求参数名stringsort
[nameSeparator]列名与状态间分隔符string.

STMultiSort

成员说明类型默认值全局配置
[key]请求参数名stringsort
[separator]不同属性间分隔符string-
[nameSeparator]列名与状态间分隔符string.
[arrayParam]是否以数组的形式传递参数
true 表示使用 url?sort=name.asc&sort=age.desc 形式
false 表示使用 url?sort=name.asc-age.desc 形式
booleanfalse
[keepEmptyKey]是否保持空值的键名
true 表示不管是否有排序都会发送 key 键名
false 表示无排序动作时不会发送 key 键名
booleantrue
[global]仅限全局配置项有效,是否全局多排序模式
true 表示所有 st 默认为多排序
false 表示需要为每个 st 添加 multiSort 才会视为多排序模式
booleantrue

STData

成员说明类型默认值
[checked]选择框或单选框状态值boolean-
[disabled]选择框或单选框 disabledboolean-
[expand]是否展开状态boolean-
[showExpand]是否显示展开按钮boolean-
[className]行样式string-

STColumn

成员说明类型默认值
[title]列名string, STColumnTitle-
[i18n]列名i18nstring-
[type]no 行号
checkbox 多选
radio 单选
link 链接,可触发 click
img 图像且居中
number 数字且居右
currency 货币且居右
date 日期格式且居中
badge 徽标
tag 标签
ynboolean类型徽章化 document
widget 自定义小部件来渲染列
string-
[index]列数据在数据项中对应的 key,支持 a.b.c 的嵌套写法string, string[]-
[render]自定义渲染IDstring, TemplateRef, TemplateRef<{ $implicit: STData; index: number }>-
[renderTitle]标题自定义渲染IDstring, TemplateRef<void>, TemplateRef<{ $implicit: STColumn; index: number }>-
[default]当不存在数据(值类型为 undefined)时以默认值替代string-
[buttons]按钮组STColumnButton[]-
[maxMultipleButton]配置最多显示多少个按钮,多余部分自动生成至 更多 下面STColumnMaxMultipleButton, number-
[width]列宽(数字型表示 px 值,注意: 若固定列必须是数字),例如:10010%100pxstring,number-
[fixed]固定前后列,当指定时务必指定 width 否则视为无效left,right-
[format]格式化列值(item: STData, col: STColumn, index: number) => string-
[className]class 属性值,例如:text-center 居中; text-right 居右; text-error 异常色,更多参考样式工具类string-
[colSpan]合并列number-
[sort]排序配置项,远程数据配置优先规则:
true 表示允许排序,且若数据源为本地数据时会自动生成 compare: (a, b) => a[index] - b[index] 方法
string 表示远程数据排序相对应 key
true,string,STColumnSort-
[filter]过滤配置项STColumnFilter-
[selections]选择功能配置STColumnSelection[]-
[numberDigits]数字格式,type=number 有效string-
[dateFormat]日期格式,type=date 有效stringyyyy-MM-dd HH:mm
[currency]货币格式选项,type=currency 有效STColumnCurrency-
[yn]type=yn 有效STColumnYn-
[exported]是否允许导出booleantrue
[acl]ACL权限,等同 can() 参数值ACLCanType-
[click]链接回调(record: STData, instance?: STComponent) => void-
[badge]徽标配置项STColumnBadge-
[tag]徽标配置项STColumnTag-
[enum]枚举配置项{ [key: string]: string; [key: number]: string }-
[widget]小部件配置项STWidgetColumn-
[noIndex]行号索引开始值number,(item: STData, col: STColumn, idx: number) => number1
[iif]条件表达式
1、仅赋值 columns 时执行一次
2、可调用 resetColumns() 再一次触发
(item: STColumn) => boolean-
[statistical]统计信息STStatisticalType,STStatistical-
[resizable]调整表头配置项,不支持多表头STResizable, boolean--
[children]多表头STColumn[]-
[safeType]安全渲染方式,支持全局配置text,html,safeHtmlsafeHtml
[customRequest]覆盖默认的请求行为,可以自定义自己的请求实现,例如:Graphql,支持全局配置(options: STCustomRequestOptions) => Observable<any>-

STColumnTitle

成员说明类型默认值
[text]列标题,texti18n 必选其一string-
[i18n]列标题i18n主键,texti18n 必选其一string-
[optional]标签可选信息string-
[optionalHelp]标签可选帮助string-

STColumnSort

成员说明类型默认值
[default]排序的受控属性ascend,descend-
[compare]本地数据的排序函数,使用一个函数(参考 Array.sort 的 compareFunction),null 忽略本地排序,但保持排序功能(a: any, b: any) => number, null-
[key]远程数据的排序时后端相对应的KEY,默认使用 index 属性
multiSort: false 时:key: 'name' => ?name=1&pi=1
multiSort: true 允许多个排序 key 存在,或使用 STMultiSort 指定多列排序key合并规则
string-
[reName]远程数据的排序时后端相对应的VALUE
{ ascend: '0', descend: '1' } 结果 ?name=1&pi=1
{ ascend: 'asc', descend: 'desc' } 结果 ?name=desc&pi=1
{ ascend?: string, descend?: string }-

STColumnFilter

成员说明类型默认值
[type]类型,keyword 文本框形式default,keyword,number,date,customdefault
[menus]表头的筛选菜单项,至少一项才会生效STColumnFilterMenu[]-
[fn]本地数据的筛选函数(filter: STColumnFilterMenu, record: STData) => boolean-
[default]标识数据是否经过过滤,筛选图标会高亮boolean-
[icon]自定义 fiter 图标
type='default' 默认 filter
type='keyword' 默认 search
string | STIconfilter
[multiple]是否多选booleantrue
[confirmText]filter 确认按钮文本string-
[clearText]filter 清除按钮文本string-
[key]远程数据的过滤时后端相对应的KEY,默认使用 index 属性string-
[reName]远程数据的过滤时后端相对应的VALUE(list: STColumnFilterMenu[], col: STColumn) => Object-
[custom]自定义模版TemplateRef<{ $implicit: STColumnFilter; col: STColumn }>-
[showOPArea]是否显示操作区域booleantrue
[placeholder]在文字框中显示提示讯息booleantrue
[number]类型为 number 的配置项Object-
[date]类型为 date 的配置项Object-

STColumnFilterMenu

成员说明类型默认值
[text]文本
type: 'keyword' 时表示 placeholder
string-
[value]any-
[checked]是否选中boolean-
[acl]权限,等同 can() 参数值ACLCanType-

STColumnButton

成员说明类型默认值
[text]文本与图标共存string | (record: STData, btn: STColumnButton) => string-
[icon]图标与文本共存string | STIcon-
[i18n]文本i18nstring-
[type]按钮类型none,del,modal,static,drawer,link-
[click]点击回调;函数: type=modal 只会在 确认 时触发且 modal 参数有效
reload: 重新刷新当前页
load: 重新加载数据,并重置页码为:1
(record: STData, modal?: any, instance?: STComponent) => void | reload-
[pop]是否需要气泡确认框boolean, string, STColumnButtonPopfalse
[modal]模态框配置STColumnButtonModal-
[drawer]抽屉配置STColumnButtonDrawer-
[children]下拉菜单,当存在时以 dropdown 形式渲染;只支持一级STColumnButton[]-
[acl]ACL权限,等同 can() 参数值ACLCanType-
[iif]自定义条件表达式(item: STData, btn: STColumnButton, column: STColumn) => boolean() => true
[iifBehavior]表达式 false 值时渲染方式hide,disabledhide
[tooltip]按钮文字提示string-
[className]按钮 class 属性值,例如:text-error 异常色,更多参考样式工具类string-

STIcon

成员说明类型默认值全局配置
[type]图标类型string--
[theme]图标主题风格outline | twotone | filloutline
[spin]是否有旋转动画booleanfalse
[twoToneColor]仅适用双色图标,设置双色图标的主要颜色,仅对当前 icon 生效string-
[iconfont]指定来自 IconFont 的图标类型string-

STColumnButtonModal

成员说明类型默认值全局配置
[component]目标组件对象any--
[params]目标组件的接收参数对象(record: STData) => Object--
[paramsName]目标组件的接收参数名,若目标组件接收值为空时,检查 global-config.module.ts 全局设置stringrecord
[size]对话框大小,支持数字类型'sm','md','lg','xl''lg'
[exact]是否精准(默认:true),若返回值非空值(nullundefined)视为成功,否则视为错误booleantrue
[includeTabs]是否包裹标签页,修复模态包含标签间距问题boolean--
[modalOptions]对话框 ModalOptions 参数any-

STColumnButtonDrawer

成员说明类型默认值全局配置
[title]标题any--
[component]目标组件对象any--
[params]目标组件的接收参数对象(record: STData) => Object--
[paramsName]目标组件的接收参数名,若目标组件接收值为空时,检查 global-config.module.ts 全局设置stringrecord
[size]抽屉大小,支持数字类型'sm','md','lg','xl''md'
[drawerOptions]抽屉 NzDrawerOptions 参数any-
[footer]是否包含底部工具条booleantrue
[footerHeight]底部工具条高度number55

STColumnSelection

成员说明类型默认值
[text]文本string-
[select]选择项点击回调,允许对参数 data.checked 进行操作(data: STData[]) => void-
[acl]ACL权限,等同 can() 参数值ACLCanType-

STColumnYn

成员说明类型默认值
[truth]真值条件anytrue
[yes]徽章 true 时文本string
[no]徽章 false 时文本string
[mode]显示模式full,icon,texticon

STcolumnCurrency

成员说明类型默认值
[type]货币渲染类型commas, megacommas
[format]CurrencyService.formatCurrencyFormatOptions-

STColumnBadge

成员说明类型默认值
[text]文本string-
[color]徽标颜色值success,processing,default,error,warning-

STColumnTag

成员说明类型默认值
[text]文本string-
[color]Tag颜色值string-

STWidgetColumn

成员说明类型默认值
[type]指定类型名,可通过定义 STWidgetRegistry 来定制,例如string-
[params]目标组件的参数(options: { record: STData; column: STColumn }) => {}-

STWidthMode

成员说明类型默认值全局配置
[type]类型strict,defaultdefault
[strictBehavior]strict 的行为类型wrap,truncatetruncate

STStatistical

成员说明类型默认值
[type]统计类型STStatisticalType | STStatisticalFn-
[digits]保留小数位数number2
[currency]是否需要货币格式化,默认当 typeSTStatisticalFnsumaveragemaxmin 时为 trueboolean-

STStatisticalFn

(
  values: number[],
  col: STColumn,
  list: STData[],
  rawData?: any,
) => STStatisticalResult

STResizable

成员说明类型默认值
[disabled]Disable resizebooleantrue
[bounds]调整尺寸的边界window, parent, ElementRef<HTMLElement>window
[maxWidth]最大宽度(超过边界部分忽略)number360
[minWidth]最小宽度number60
[preview]开启预览booleantrue

Theme

成员说明默认值
@nz-table-img-radius图像圆角大小4px
@nz-table-img-margin-right图像右边距4px
@nz-table-img-max-height图像最大高度32px
@nz-table-img-max-width图像最大宽度32px
@nz-table-even-background行奇偶背景色none
@nz-table-rep-max-width可视区域小于时触发
@nz-table-rep-min-width可视区域大于时触发
@nz-table-rep-header-background响应式下标题背景颜色@border-color-split
@nz-table-rep-even-background响应式下奇偶颜色#f9f9f9
@nz-table-rep-column-name-color响应式下文本颜色rgba(0, 0, 0, 0.5)
@nz-table-rep-column-name-text-align响应式下标题文本对齐方式right
@nz-table-rep-column-name-width响应式下标题宽度100px
@nz-table-rep-column-name-padding-right响应式下标题与内容右边距8px
@table-row-hover-bg行悬停背景色#fafafa
@st-btn-disabled-color禁用按钮的文本颜色rgba(0, 0, 0, 0.25)
@st-title-optional-color标题可选文本颜色rgba(0, 0, 0, 0.35)
@st-resizable-handle-width拖拽宽度1px
@st-resizable-handle-height拖拽高度60%
@st-resizable-handle-color拖拽颜色@border-color-base