表格
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头像邮箱aaa1@qq.com电话phone-99053佣金(单位:元)5,452,248注册时间2022-06-06 06:38
编号2头像邮箱aaa8@qq.com电话phone-96349佣金(单位:元)3,520,322注册时间2022-06-06 06:38
编号3头像邮箱aaa6@qq.com电话phone-90350佣金(单位:元)9,260,394注册时间2022-06-06 06:38
  • 1
  • 基本

    快速生成表格;利用 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状态DefaultDate2022-06-06 06:38
    编号姓名name 2年龄27状态SuccessDate2022-06-06 06:38
    编号姓名name 3年龄22状态ProcessingDate2022-06-06 06:38
  • 1
  • 2
  • 3
  • 4
  • 5
  • •••
  • 34
  • 自定义数据

    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);
      }
    }
  • 共 10 条
  • 1
  • 2
  • 3
  • 4
  • 行号姓名年龄HTMLTexttagbadgeEnumyn
    行号1姓名name 1年龄31HTML1 OtherText<strong>1</strong> Othertag进行中badge成功Enumyn
    行号2姓名name 2年龄30HTML2 OtherText<strong>2</strong> Othertag错误badge成功Enumyn
    行号3姓名name 3年龄38HTML3 OtherText<strong>3</strong> Othertag默认badge默认Enumyn
  • 共 10 条
  • 1
  • 2
  • 3
  • 4
  • 列类型

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

    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-61805注册时间2022-06-06 06:38
    编号头像邮箱aaa10@qq.com电话phone-29974注册时间2022-06-06 06:38
    编号头像邮箱aaa8@qq.com电话phone-89774注册时间2022-06-06 06:38
  • 1
  • 2
  • 3
  • 4
  • 5
  • •••
  • 34
  • 可选择

    利用 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;
        });
      }
    }
    编号头像邮箱电话注册时间
    编号头像邮箱aaa1@qq.com电话phone-25556注册时间2022-06-06 06:38
    编号头像邮箱aaa2@qq.com电话phone-87518注册时间2022-06-06 06:38
    编号头像邮箱aaa1@qq.com电话phone-78178注册时间2022-06-06 06:38
  • 1
  • 2
  • 3
  • 4
  • 5
  • •••
  • 100
  • 单选框

    利用 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邮箱aaa5@qq.com电话phone-86432注册时间2022-06-06 06:38
    编号2邮箱aaa6@qq.com电话phone-91404注册时间2022-06-06 06:38
    编号3邮箱aaa4@qq.com电话phone-60322注册时间2022-06-06 06:38
  • 1
  • 右键菜单

    利用 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年龄21启用YOPEdit
    编号2姓名name 2年龄29启用NOPEdit
    编号3姓名name 3年龄24启用YOPEdit
  • 1
  • 2
  • 3
  • 4
  • 可编辑行

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

    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头像邮箱aaa9@qq.com电话phone-70548注册时间2022-06-06 06:38
    编号2头像邮箱aaa2@qq.com电话phone-21176注册时间2022-06-06 06:38
    编号3头像邮箱aaa7@qq.com电话phone-19721注册时间2022-06-06 06:38
  • 1
  • 2
  • 3
  • 4
  • 5
  • •••
  • 34
  • 搜索表单

    配合 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邮箱aaa7@qq.com电话phone-19401
    编号2邮箱aaa2@qq.com电话phone-88057
    编号3邮箱aaa7@qq.com电话phone-30552
  • 1
  • 2
  • 3
  • 4
  • 5
  • •••
  • 34
  • 行操作

    利用 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-10 first-15国家CH性别male注册时间2022-06-06 06:38
    编号2头像姓名2: last-2 first-17国家US性别female注册时间2022-06-06 06:38
    编号3头像姓名3: last-4 first-18国家DE性别male注册时间2022-06-06 06:38
  • 1
  • 2
  • 3
  • 4
  • 5
  • •••
  • 67
  • 后端筛选和排序

    利用 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年龄29Button
    编号2姓名name 2年龄28Button
    编号3姓名name 3年龄21Button
  • 1
  • 2
  • 3
  • 4
  • 可展开

    使用 #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年龄25自定义tooltip: 25-0
    编号2姓名name 2年龄24自定义tooltip: 24-1
    编号3姓名name 3年龄27自定义tooltip: 27-2
  • 1
  • 2
  • 3
  • 4
  • 自定义列

    创建一个带有 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年龄26操作区EditDrawer更多
    序号2编号2姓名name 2年龄21操作区EditDrawer更多
    序号3编号3姓名name 3年龄29操作区EditDrawer更多
  • 1
  • 2
  • 3
  • 4
  • 自定义按钮组

    透过简单的配置产生一组日常按钮组(目标组件示例: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自定义头像邮箱aaa5@qq.com
    编号2自定义头像邮箱aaa2@qq.com
    编号3自定义头像邮箱aaa3@qq.com
  • 1
  • 2
  • 3
  • 4
  • 5
  • •••
  • 34
  • 自定义小部件

    类型为 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年龄1225
    编号12编号22编号32编号42编号52编号62编号72编号82编号82编号82编号82编号82姓名10name 2姓名11name 2年龄1228
    编号13编号23编号33编号43编号53编号63编号73编号83编号83编号83编号83编号83姓名10name 3姓名11name 3年龄1225
  • 1
  • 2
  • 3
  • 4
  • 固定列

    对于列数很多的数据,可以使用 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-19lastlast-8
    编号2头像邮箱aaa4@qq.comfirstfirst-20lastlast-10
    编号3头像邮箱aaa7@qq.comfirstfirst-12lastlast-7
  • 1
  • 表头分组

    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头像邮箱aaa8@qq.com电话phone-46642注册时间2022-06-06 06:38
    编号2头像邮箱aaa10@qq.com电话phone-17958注册时间2022-06-06 06:38
    编号3头像邮箱aaa5@qq.com电话phone-85455注册时间2022-06-06 06:38
    The footer
  • 1
  • 2
  • 3
  • 4
  • 5
  • •••
  • 34
  • 响应式

    小屏幕下将以响应模式堆叠显示,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性别Sum0Average0Min0Max0Custom0
    行号2编号2性别Sum55Average55Min55Max55Custom55
    行号3编号3性别Sum78Average78Min78Max78Custom78
    合计3 个113344.330780
    性别平均值44.33
  • 1
  • 2
  • 3
  • 4
  • 5
  • •••
  • 34
  • 统计

    支持 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数字18,949,793货币18,949,793注册时间2022-06-06 06:38
    编号2头像邮箱e2@qq.com电话phone - 2数字11,647,284货币11,647,284注册时间2022-06-06 06:38
    编号3头像邮箱e3@qq.com电话phone - 3数字18,646,995货币18,646,995注册时间2022-06-06 06:38
  • 1
  • 2
  • 3
  • 4
  • 5
  • •••
  • 3334
  • 导出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头像邮箱aaa2@qq.com电话phone-11795佣金2,510,038注册时间2022-06-06 06:38
    编号2头像邮箱aaa3@qq.com电话phone-71970佣金2,263,564注册时间2022-06-06 06:38
    编号3头像邮箱aaa4@qq.com电话phone-64340佣金1,273,702注册时间2022-06-06 06:38
  • 1
  • 调整尺寸

    基于 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--
    [method]请求方法'POST','GET','HEAD','PUT','PATCH','DELETE''GET'
    [body]请求体 body,当 method: POST 时有效any--
    [headers]请求体 headersany-
    [reName]重命名请求参数 pipsSTReqReNameType{ 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