ng-alain组件开发Skill ng-alain-component-development

使用ng-alain和ng-zorro-antd开发企业级UI组件,包括数据表格、表单、访问控制、响应式布局和主题系统等关键技术。

前端开发 0 次安装 1 次浏览 更新于 2/28/2026

ng-alain 组件开发技能

这个技能帮助使用 ng-alain 和 ng-zorro-antd 创建企业级 UI 组件。

核心库

@delon 包

  • @delon/abc: 业务组件(ST, SV, SEModule 等)
  • @delon/form: 动态基于模式的表单(SF)
  • @delon/auth: 认证和授权
  • @delon/acl: 访问控制列表
  • @delon/theme: 主题和布局系统
  • @delon/util: 工具函数

ng-zorro-antd

  • 完整的 Ant Design 组件库
  • 图标、布局、表单、表格、模态框等。

常见模式

1. ST(简单表格)组件

import { Component, signal, inject } from '@angular/core';
import { STColumn, STData, STComponent } from '@delon/abc/st';
import { SHARED_IMPORTS } from '@shared';

@Component({
  selector: 'app-task-table',
  standalone: true,
  imports: [SHARED_IMPORTS, STComponent],
  template: `
    <st 
      [data]="tasks()" 
      [columns]="columns"
      [loading]="loading()"
      [page]="{ show: true, showSize: true }"
      (change)="handleChange($event)"
    />
  `
})
export class TaskTableComponent {
  private taskService = inject(TaskService);
  
  loading = signal(false);
  tasks = signal<STData[]>([]);
  
  columns: STColumn[] = [
    { 
      title: 'ID', 
      index: 'id', 
      width: 80,
      fixed: 'left'
    },
    { 
      title: '标题', 
      index: 'title',
      width: 200
    },
    { 
      title: '状态', 
      index: 'status', 
      type: 'badge',
      badge: {
        pending: { text: '待处理', color: 'processing' },
        'in-progress': { text: '进行中', color: 'warning' },
        completed: { text: '已完成', color: 'success' }
      }
    },
    {
      title: '指派人',
      index: 'assigneeName',
      width: 150
    },
    {
      title: '截止日期',
      index: 'dueDate',
      type: 'date',
      dateFormat: 'yyyy-MM-dd'
    },
    {
      title: '操作',
      buttons: [
        {
          text: '编辑',
          icon: 'edit',
          click: (record: any) => this.edit(record)
        },
        {
          text: '删除',
          icon: 'delete',
          type: 'del',
          pop: {
            title: '确认删除?',
            okType: 'danger'
          },
          click: (record: any) => this.delete(record)
        }
      ]
    }
  ];
  
  ngOnInit(): void {
    this.loadTasks();
  }
  
  async loadTasks(): Promise<void> {
    this.loading.set(true);
    try {
      const tasks = await this.taskService.getTasks();
      this.tasks.set(tasks);
    } finally {
      this.loading.set(false);
    }
  }
  
  handleChange(event: any): void {
    console.log('表格变化:', event);
  }
  
  edit(record: any): void {
    console.log('编辑:', record);
  }
  
  delete(record: any): void {
    console.log('删除:', record);
  }
}

2. SF(模式表单)组件

import { Component, signal, inject, output } from '@angular/core';
import { SFSchema, SFComponent } from '@delon/form';
import { SHARED_IMPORTS } from '@shared';

@Component({
  selector: 'app-task-form',
  standalone: true,
  imports: [SHARED_IMPORTS, SFComponent],
  template: `
    <sf 
      [schema]="schema" 
      [loading]="loading()"
      (formSubmit)="handleSubmit($event)"
      (formChange)="handleChange($event)"
    />
  `
})
export class TaskFormComponent {
  loading = signal(false);
  taskSubmit = output<any>();
  
  schema: SFSchema = {
    properties: {
      title: {
        type: 'string',
        title: '任务标题',
        maxLength: 200,
        ui: {
          placeholder: '输入任务标题',
          grid: { span: 24 }
        }
      },
      description: {
        type: 'string',
        title: '描述',
        ui: {
          widget: 'textarea',
          autosize: { minRows: 3, maxRows: 6 },
          grid: { span: 24 }
        }
      },
      status: {
        type: 'string',
        title: '状态',
        enum: [
          { label: '待处理', value: 'pending' },
          { label: '进行中', value: 'in-progress' },
          { label: '已完成', value: 'completed' }
        ],
        default: 'pending',
        ui: {
          widget: 'select',
          grid: { span: 12 }
        }
      },
      priority: {
        type: 'string',
        title: '优先级',
        enum: [
          { label: '低', value: 'low' },
          { label: '中', value: 'medium' },
          { label: '高', value: 'high' }
        ],
        default: 'medium',
        ui: {
          widget: 'radio',
          grid: { span: 12 }
        }
      },
      assignee: {
        type: 'string',
        title: '指派人',
        ui: {
          widget: 'select',
          asyncData: () => this.loadUsers(),
          grid: { span: 12 }
        }
      },
      dueDate: {
        type: 'string',
        title: '截止日期',
        format: 'date',
        ui: {
          widget: 'date',
          grid: { span: 12 }
        }
      },
      tags: {
        type: 'array',
        title: '标签',
        items: {
          type: 'string'
        },
        ui: {
          widget: 'select',
          mode: 'tags',
          grid: { span: 24 }
        }
      }
    },
    required: ['title', 'assignee'],
    ui: {
      grid: { gutter: 16 }
    }
  };
  
  handleSubmit(value: any): void {
    console.log('表单提交:', value);
    this.taskSubmit.emit(value);
  }
  
  handleChange(value: any): void {
    console.log('表单变化:', value);
  }
  
  private async loadUsers(): Promise<any[]> {
    // 加载用户以供指派人下拉选择
    return [
      { label: '用户1', value: 'user1' },
      { label: '用户2', value: 'user2' }
    ];
  }
}

3. 页面头部与操作

import { Component } from '@angular/core';
import { PageHeaderComponent } from '@delon/abc/page-header';
import { SHARED_IMPORTS } from '@shared';

@Component({
  selector: 'app-task-page',
  standalone: true,
  imports: [SHARED_IMPORTS, PageHeaderComponent],
  template: `
    <page-header 
      [title]="'任务管理'"
      [subtitle]="'管理 ' + blueprintName()"
      [breadcrumb]="breadcrumb"
    >
      <ng-template #extra>
        <button nz-button nzType="primary" (click)="createTask()">
          <i nz-icon nzType="plus"></i>
          新任务
        </button>
        <button nz-button (click)="refresh()">
          <i nz-icon nzType="reload"></i>
          刷新
        </button>
      </ng-template>
    </page-header>
    
    <nz-card>
      <app-task-table />
    </nz-card>
  `
})
export class TaskPageComponent {
  blueprintName = signal('我的蓝图');
  
  breadcrumb = [
    { title: '首页', link: '/' },
    { title: '蓝图', link: '/blueprints' },
    { title: '任务' }
  ];
  
  createTask(): void {
    console.log('创建新任务');
  }
  
  refresh(): void {
    console.log('刷新任务');
  }
}

4. ACL(访问控制)

import { Component, inject } from '@angular/core';
import { ACLService } from '@delon/acl';
import { SHARED_IMPORTS } from '@shared';

@Component({
  selector: 'app-task-actions',
  standalone: true,
  imports: [SHARED_IMPORTS],
  template: `
    <nz-space>
      <!-- 仅当用户有权限时显示按钮 -->
      <button 
        *nzSpaceItem
        *aclIf="'task:create'"
        nz-button 
        nzType="primary"
        (click)="create()"
      >
        创建任务
      </button>
      
      <button 
        *nzSpaceItem
        *aclIf="'task:delete'"
        nz-button 
        nzDanger
        (click)="delete()"
      >
        删除
      </button>
      
      <!-- 在代码中检查权限 -->
      @if (canEdit()) {
        <button 
          *nzSpaceItem
          nz-button 
          (click)="edit()"
        >
          编辑
        </button>
      }
    </nz-space>
  `
})
export class TaskActionsComponent {
  private aclService = inject(ACLService);
  
  canEdit = signal(false);
  
  ngOnInit(): void {
    // 程序性检查权限
    this.canEdit.set(this.aclService.can('task:edit'));
  }
  
  create(): void {
    console.log('创建任务');
  }
  
  edit(): void {
    console.log('编辑任务');
  }
  
  delete(): void {
    console.log('删除任务');
  }
}

5. 响应式布局

import { Component } from '@angular/core';
import { SHARED_IMPORTS } from '@shared';

@Component({
  selector: 'app-dashboard',
  standalone: true,
  imports: [SHARED_IMPORTS],
  template: `
    <div nz-row [nzGutter]="[16, 16]">
      <!-- 响应式列 -->
      <div nz-col [nzXs]="24" [nzSm]="12" [nzMd]="8" [nzLg]="6">
        <nz-card nzTitle="总任务数">
          <nz-statistic 
            [nzValue]="totalTasks()" 
            [nzPrefix]="prefixTpl"
          />
          <ng-template #prefixTpl>
            <i nz-icon nzType="check-circle"></i>
          </ng-template>
        </nz-card>
      </div>
      
      <div nz-col [nzXs]="24" [nzSm]="12" [nzMd]="8" [nzLg]="6">
        <nz-card nzTitle="已完成">
          <nz-statistic 
            [nzValue]="completedTasks()" 
            [nzValueStyle]="{ color: '#52c41a' }"
          />
        </nz-card>
      </div>
      
      <div nz-col [nzXs]="24" [nzSm]="12" [nzMd]="8" [nzLg]="6">
        <nz-card nzTitle="进行中">
          <nz-statistic 
            [nzValue]="inProgressTasks()" 
            [nzValueStyle]="{ color: '#faad14' }"
          />
        </nz-card>
      </div>
      
      <div nz-col [nzXs]="24" [nzSm]="12" [nzMd]="8" [nzLg]="6">
        <nz-card nzTitle="待处理">
          <nz-statistic [nzValue]="pendingTasks()" />
        </nz-card>
      </div>
    </div>
  `
})
export class DashboardComponent {
  totalTasks = signal(100);
  completedTasks = signal(60);
  inProgressTasks = signal(25);
  pendingTasks = signal(15);
}

6. 模态框和抽屉

import { Component, inject } from '@angular/core';
import { NzModalService } from 'ng-zorro-antd/modal';
import { NzDrawerService } from 'ng-zorro-antd/drawer';
import { SHARED_IMPORTS } from '@shared';
import { TaskFormComponent } from './task-form.component';

@Component({
  selector: 'app-task-manager',
  standalone: true,
  imports: [SHARED_IMPORTS],
  template: `
    <button nz-button nzType="primary" (click)="openModal()">
      打开模态框
    </button>
    <button nz-button (click)="openDrawer()">
      打开抽屉
    </button>
  `
})
export class TaskManagerComponent {
  private modal = inject(NzModalService);
  private drawer = inject(NzDrawerService);
  
  openModal(): void {
    const modalRef = this.modal.create({
      nzTitle: '创建任务',
      nzContent: TaskFormComponent,
      nzWidth: 720,
      nzFooter: null
    });
    
    // 监听表单提交
    modalRef.componentInstance!.taskSubmit.subscribe((task: any) => {
      console.log('任务提交:', task);
      modalRef.close();
    });
  }
  
  openDrawer(): void {
    const drawerRef = this.drawer.create({
      nzTitle: '任务详情',
      nzContent: TaskFormComponent,
      nzWidth: 640,
      nzClosable: true
    });
    
    drawerRef.afterClose.subscribe(() => {
      console.log('抽屉关闭');
    });
  }
}

ng-alain 主题

使用主题变量

// 使用 ng-alain 主题变量
@import '@delon/theme/system/index';

.task-card {
  background: var(--bg-color);
  border: 1px solid var(--border-color);
  padding: var(--padding-lg);
  
  .title {
    color: var(--text-color);
    font-size: var(--font-size-lg);
  }
}

暗色模式支持

import { Component, inject } from '@angular/core';
import { SettingsService } from '@delon/theme';

@Component({
  selector: 'app-theme-toggle',
  template: `
    <button nz-button (click)="toggleTheme()">
      <i nz-icon [nzType]="isDark() ? 'sun' : 'moon'"></i>
      {{ isDark() ? '浅色' : '暗色' }} 模式
    </button>
  `
})
export class ThemeToggleComponent {
  private settings = inject(SettingsService);
  
  isDark = signal(false);
  
  ngOnInit(): void {
    this.isDark.set(this.settings.layout.theme === 'dark');
  }
  
  toggleTheme(): void {
    const newTheme = this.isDark() ? 'light' : 'dark';
    this.settings.setLayout('theme', newTheme);
    this.isDark.set(newTheme === 'dark');
  }
}

最佳实践

1. 使用 SHARED_IMPORTS

// 在共享模块中定义
export const SHARED_IMPORTS = [
  CommonModule,
  ReactiveFormsModule,
  // ng-zorro-antd
  NzButtonModule,
  NzCardModule,
  NzFormModule,
  NzInputModule,
  // @delon
  STComponent,
  SFComponent,
  PageHeaderComponent
];

2. 响应式设计

// 使用 ng-zorro 响应式工具
<div nz-row [nzGutter]="16">
  <div nz-col 
    [nzXs]="24"  // 手机:全宽
    [nzSm]="12"  // 平板:半宽
    [nzMd]="8"   // 桌面:三分之一宽
    [nzLg]="6"   // 大屏:四分之一宽
  >
    内容
  </div>
</div>

3. 可访问性

<!-- 使用适当的 ARIA 属性 -->
<button 
  nz-button 
  aria-label="创建新任务"
  [attr.aria-disabled]="loading()"
>
  创建
</button>

<!-- 适当的表单标签 -->
<nz-form-item>
  <nz-form-label nzFor="title" nzRequired>
    任务标题
  </nz-form-label>
  <nz-form-control>
    <input nz-input id="title" name="title" />
  </nz-form-control>
</nz-form-item>

检查清单

创建 ng-alain 组件时:

  • [ ] 使用独立组件
  • [ ] 导入 SHARED_IMPORTS
  • [ ] 使用 STComponent 制作数据表格
  • [ ] 使用 SFComponent 制作复杂表单
  • [ ] 实现响应式布局
  • [ ] 需要时添加 ACL 权限
  • [ ] 使用 PageHeader 制作页面标题
  • [ ] 实现适当的加载状态
  • [ ] 添加错误处理
  • [ ] 遵循 ng-alain 主题系统
  • [ ] 支持暗色模式
  • [ ] 确保可访问性(ARIA)
  • [ ] 在移动设备上测试

参考资料