项目

页面组件

ABP提供了一个组件,可将您的内容与多个内置组件进行封装,从而减少需要编写的代码量。

如果某个组件的模板如下所示,您就可以使用abp-page组件。

我们先来看一个未使用abp-page组件的示例:

dashboard.component.ts

<div class="row entry-row">
  <div class="col-auto">
    <h1 class="content-header-title">{{ '::Dashboard' | abpLocalization }}</h1>
  </div>
  <div id="breadcrumb" class="col-lg-auto pl-lg-0">
    <abp-breadcrumb />
  </div>
  <div class="col">
    <abp-page-toolbar [record]="data" />
  </div>
</div>

<div id="dashboard-id">
  <!-- 仪表板内容放置处 -->
</div>

页面组成部分

PageComponent将上述模板划分为三个部分:title(标题)、breadcrumb(面包屑导航)、toolbar(工具栏)。每个部分都可以单独配置。该包还导出了一个枚举,用于描述各个部分:

export enum PageParts {
  title = 'PageTitleContainerComponent',
  breadcrumb = 'PageBreadcrumbContainerComponent',
  toolbar = 'PageToolbarContainerComponent',
}

// 可通过以下方式导入该枚举 -> import { PageParts } from '@abp/ng.components/page';

使用方法

首先,根据使用需求从@abp/ng.components/page导入页面组件。示例如下:

dashboard.component.ts

@Component({
  imports: [ PageComponent, ... ]
})
export class DashboardComponent {}

然后将dashboard.component.html的模板修改为:

<abp-page [title]="'::Dashboard' | abpLocalization" [toolbar]="data">
  <div id="dashboard-id">
    <!-- .... -->
  </div>
</abp-page>

输入参数

  • title: string:将在h1.content-header-title中渲染。若不提供,父级div将不会渲染
  • breadcrumb: boolean:决定是否渲染abp-breadcrumb。默认为true
  • toolbar: any:将通过record输入参数传递给abp-page-toolbar组件。如果页面不包含abp-page-toolbar,可直接忽略此字段

模板重写

如需替换任何部分的模板,可使用以下子组件。您需要导入这些组件并相应修改HTML模板:

import { 
  PageComponent, 
  PageTitleContainerComponent,
  PageBreadcrumbContainerComponent,
  PageToolbarContainerComponent
} from '@abp/ng.components/page';

@Component({
  selector: 'app-sample-component',
  template: `
    <abp-page>
      <abp-page-title-container class="col">
        <h2>自定义标题</h2>
      </abp-page-title-container>

      <abp-page-breacrumb-container class="col">
        <my-breadcrumb />
      </abp-page-breacrumb-container>

      <abp-page-toolbar-container class="col">
        <button (click)="doSth()">操作按钮</button>
      </abp-page-toolbar-container>
    </abp-page>
  `,
  imports: [
    PageComponent, 
    PageTitleContainerComponent, 
    PageBreadcrumbContainerComponent, 
    MyBreadcrumbComponent,
    PageToolbarContainerComponent
  ]
})
export class SampleComponent {}

无需全部提供这些组件,只需使用需要替换的部分即可。这些组件的优先级高于上述声明的输入参数。使用这些组件时,可省略对应的输入参数。

PagePartDirective

Components包提供了一个结构指令,该指令在PageComponent内部使用,也可在外部使用。

PageComponent内部使用该指令的方式如下:

<div class="col-lg-auto pl-lg-0" *abpPagePart="pageParts.breadcrumb">
  <abp-breadcrumb />
</div>

该指令还可接收上下文输入参数:

<div class="col" *abpPagePart="pageParts.toolbar; context: toolbarData">
  <abp-page-toolbar [record]="toolbarData" />
</div>

其渲染策略可通过Angular的依赖注入系统提供。

该指令期望通过PAGE_RENDER_STRATEGY注入令牌获取一个服务,该服务需实现以下接口:

interface PageRenderStrategy {
  shouldRender(type?: string): boolean | Observable<boolean>;
  onInit?(type?: string, injector?: Injector, context?: any): void;
  onDestroy?(type?: string, injector?: Injector, context?: any): void;
  onContextUpdate?(change?: SimpleChange): void;
}
  • shouldRender(必需):接收名为type的字符串输入,并返回booleanObservable<boolean>
  • onInit(可选):在指令初始化时调用。将传入三个参数:
    • type:页面部件类型
    • injector:指令的注入器,可用于从指令的DI树中获取任何内容
    • context:初始化阶段可用的任意上下文
  • onDestroy(可选):在指令销毁时调用。参数与onInit相同
  • onContextUpdate(可选):在上下文更新时调用
    • changecontext的变更将通过此方法传递

让我们通过完整示例了解具体用法:

import { 
  PageModule,
  PageRenderStrategy, 
  PageParts,
  PAGE_RENDER_STRATEGY
} from '@abp/ng.components/page';

@Injectable()
export class MyPageRenderStrategy implements PageRenderStrategy {
  shouldRender(type: string) {
    // 表示除breadcrumb和custom-part外,其他部分都会渲染
    return type !== PageParts.breadcrumb && type !== 'custom-part';
  }

  /**
   * shouldRender也可返回Observable<boolean>,
   * 这意味着可以在其中使用异步服务

  service = inject(SomeAsyncService)

  shouldRender(type: string) {
    return this.service.checkTypeAsync(type).pipe(map(val => val.isTrue()));
  }
  */
   
  onInit(type: string, injector: Injector, context: any) {
    // 该方法将在指令的ngOnInit中调用
  }

  onDestroy(type: string, injector: Injector, context: any) {
    // 该方法将在指令的ngOnDestroy中调用
  }

  onContextUpdate?(change?: SimpleChange) {
    // 每次指令内上下文更新时都会调用此方法
  }
}

@Component({
  selector: 'app-dashboard',
  template: `
    <abp-page [title]="'::Dashboard' | abpLocalization">
      <abp-page-toolbar-container>
        <button>新建仪表板</button>
      </abp-page-toolbar-container>

      <div class="dashboard-content">
        <h3 *abpPagePart="'custom-part'"> 内部标题 </h3>
      </div>
    </abp-page>
  `
})
export class DashboardComponent {}

export const appConfig: ApplicationConfig = {
  providers: [
    {
      provide: PAGE_RENDER_STRATEGY,
      useClass: MyPageRenderStrategy,
    }
  ],
};

另请参阅

在本文档中