Angular UI v2.9 迁移到 v3.0 指南

    如何迁移?

    在你的根文件夹中打开一个终端,然后运行以下命令:

    这会做如下修改:

    • 更新你的package.json并安装新的软件包
    • 修改tsconfig.json文件创建一个”Solution Style”配置
    • 重命名 为 .browserslistrc

    另一方面,如果你单独使用 yarn ng update 命令检查首先要更新哪些包会更好. Angular会给你一个要更新的包列表.

    当Angular报告上面的包后,运行命令:

    1. yarn ng update @angular/cli @angular/core ng-zorro-antd --force

    配置模块

    在ABP v2.x中,每个延迟加载的模块都有一个可通过单独的程序包使用的配置模块,模块配置如下:

    1. import { AccountConfigModule } from '@abp/ng.account.config';
    2. @NgModule({
    3. imports: [
    4. // other imports
    5. AccountConfigModule.forRoot({ redirectUrl: '/' }),
    6. ],
    7. // providers, declarations, and bootstrap
    8. })
    9. export class AppModule {}

    …在app-routing.module.ts…

    1. const routes: Routes = [
    2. // other route configuration
    3. {
    4. path: 'account',
    5. loadChildren: () => import(
    6. './lazy-libs/account-wrapper.module'
    7. ).then(m => m.AccountWrapperModule),
    8. },
    9. ];

    虽然有效,但有一些缺点:

    • 每个模块都有两个独立的程序包,但实际上这些程序包是相互依赖的.
    • 配置延迟加载的模块需要包装模块.
    • ABP Commercial具有可扩展性系统,在根模块上配置可扩展模块会增加 bundle 的大小.

    在ABP v3.0中,我们为每个配置模块引入了辅助入口点,并且提供了一种在没有包装的情况下配置延迟加载的模块的新方法. 现在模块配置如下所示:

    … 在app-routing.module.ts…

    1. const routes: Routes = [
    2. // other route configuration
    3. {
    4. path: 'account',
    5. loadChildren: () => import('@abp/ng.account')
    6. .then(m => m.AccountModule.forLazy({ redirectUrl: '/' })),
    7. },
    8. ];

    一个更好的例子

    AppModule:

    1. import { AccountConfigModule } from '@abp/ng.account/config';
    2. import { CoreModule } from '@abp/ng.core';
    3. import { IdentityConfigModule } from '@abp/ng.identity/config';
    4. import { SettingManagementConfigModule } from '@abp/ng.setting-management/config';
    5. import { TenantManagementConfigModule } from '@abp/ng.tenant-management/config';
    6. import { ThemeBasicModule } from '@abp/ng.theme.basic';
    7. import { ThemeSharedModule } from '@abp/ng.theme.shared';
    8. import { NgModule } from '@angular/core';
    9. import { BrowserModule } from '@angular/platform-browser';
    10. import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
    11. import { NgxsModule } from '@ngxs/store';
    12. import { environment } from '../environments/environment';
    13. import { AppRoutingModule } from './app-routing.module';
    14. @NgModule({
    15. imports: [
    16. BrowserAnimationsModule,
    17. AppRoutingModule,
    18. CoreModule.forRoot({
    19. environment,
    20. sendNullsAsQueryParam: false,
    21. skipGetAppConfiguration: false,
    22. }),
    23. ThemeSharedModule.forRoot(),
    24. AccountConfigModule.forRoot(),
    25. IdentityConfigModule.forRoot(),
    26. TenantManagementConfigModule.forRoot(),
    27. SettingManagementConfigModule.forRoot(),
    28. ThemeBasicModule.forRoot(),
    29. NgxsModule.forRoot(),
    30. ],
    31. // providers, declarations, and bootstrap
    32. })
    33. export class AppModule {}

    AppRoutingModule:

    1. import { NgModule } from '@angular/core';
    2. import { RouterModule, Routes } from '@angular/router';
    3. const routes: Routes = [
    4. {
    5. path: '',
    6. pathMatch: 'full',
    7. loadChildren: () => import('./home/home.module').then(m => m.HomeModule),
    8. },
    9. {
    10. loadChildren: () =>
    11. import('@abp/ng.account').then(m => m.AccountModule.forLazy({ redirectUrl: '/' })),
    12. },
    13. {
    14. path: 'identity',
    15. loadChildren: () => import('@abp/ng.identity').then(m => m.IdentityModule.forLazy()),
    16. },
    17. {
    18. path: 'tenant-management',
    19. loadChildren: () =>
    20. import('@abp/ng.tenant-management').then(m => m.TenantManagementModule.forLazy()),
    21. },
    22. {
    23. path: 'setting-management',
    24. loadChildren: () =>
    25. import('@abp/ng.setting-management').then(m => m.SettingManagementModule.forLazy()),
    26. },
    27. ];
    28. @NgModule({
    29. imports: [RouterModule.forRoot(routes)],
    30. exports: [RouterModule],
    31. })
    32. export class AppRoutingModule {}

    你可能已经注意到我们在AppComponent模板中使用了 <abp-dynamic-layout> 而不是 <router-outlet>. 我们这样做是为了避免不必要的渲染和闪烁. 这不是强制的,但是我们建议在你的应用程序路由中做同样的事情.

    如何迁移?

    • 使用 yarn remove 删除你的项目的配置包.
    • 从辅助入口点(例如@abp/ng.identity/config)导入配置模块.
    • 调用所有新配置模块的静态 forRoot方法,即使配置没有被传递.
    • 调用 ThemeBasicModule 的静态 forRoot 方法(或商业上的 ThemeLeptonModule),并从导入中删除 SharedModule(除非已在其中添加了根模块所需的任何内容).
    • 在app路由模块中直接导入延迟ABP模块 (如 () => import('@abp/ng.identity').then(...)).
    • 在所有延迟模块 then 中调用的静态 forLazy 方法,即使配置没有被传递.
    • [可选]添加 <abp-dynamic-layout></abp-dynamic-layout> 到AppComponent模板并且删除 <router-outlet></router-outlet>,获得更好的性能和UX.

    在ABP v2.x中,通过以下两种方式之一将路由添加到菜单:

    从v3.0开始,我们更改了添加和修改路由的方式. 我们不再将路由存储在 ConfigState中(破坏性更改). 而是有一个名为 RoutesService 的新服务,该服务用于添加,修补或删除菜单项. 详情请查看.

    如何迁移?

    • 检查你是否曾经使用 ConfigStateConfigStateService 添加路由. 请用 RoutesServiceadd 方法替换它们.
    • 检查你是否曾经修补的路由. 将其替换为 RoutesServicepatch 方法.
    • 仔细检查你是否使用绝对路径,并在 addpatch 方法调用中为子菜单项提供 parentName 而不是 children 属性.

    NavItemsService

    在ABP v2.x中,通过LayoutStateService添加导航元素.

    从v3.0开始,我们改变了添加和修改导航项的方式,以前的方法不再可用(破坏性更改). 详情请查看.

    如何迁移?

    • NavItemsServiceaddItems 方法替换所有 dispatchAddNavigationElement 调用.

    在v3之前,我们一直使用自定义组件 abp-table 作为默认表. 但是数据表是复杂的组件,要实现功能齐全的数据表需要大量的精力,我们计划将其引入其他功能.

    从ABP v3开始,我们已切换到经过严格测试,执行良好的数据表格:. 所有的ABP模块都已经实现了ngx-datatable. ThemeSharedModule 已经导出了 NgxDatatableModule. 因此如果你在终端运行 yarn add @swimlane/ngx-datatable 来安装这个包,它将在你的应用的所有模块中可用.

    为了正确设置样式,你需要在angular.json文件的样式部分中添加以下内容(在其他所有元素之上):

    由于尚未删除 abp-table, 因此以前由ABP v2.x构建的模块不会突然丢失所有. 但是它们的外观与内置ABP v3模块有所不同, 因此你可能希望将这些模块中的表转换为ngx-datatable. 为了减少将abp-table转换为ngx-datatable所需的工作量,我们修改了 ListService 以使其与 ngx-datatable 一起很好地工作,并引入了两个新指令: NgxDatatableListDirectiveNgxDatatableDefaultDirective.

    1. @Component({
    2. providers: [ListService],
    3. })
    4. export class SomeComponent {
    5. query => this.dataService.get(query)
    6. );
    7. constructor(
    8. public readonly list: ListService,
    9. public readonly dataService: SomeDataService,
    10. ) {}
    11. }

    …在组件模板…

    1. <ngx-datatable
    2. [count]="(data$ | async)?.totalCount || 0"
    3. [list]="list"
    4. default
    5. >
    6. <!-- column templates here -->
    7. </ngx-datatable>

    通过 NgxDatatableListDirective 绑定注入的 ListService 实例后,你不再需要担心分页或排序. 同样 NgxDatatableDefaultDirective 去除了几个属性绑定,以使ngx-datatable适合我们的样式.

    一个更好的例子

    1. <ngx-datatable
    2. [rows]="items"
    3. [count]="count"
    4. [list]="list"
    5. default
    6. >
    7. <!-- the grid actions column -->
    8. <ngx-datatable-column
    9. name=""
    10. [maxWidth]="150"
    11. [width]="150"
    12. [sortable]="false"
    13. >
    14. <ng-template
    15. ngx-datatable-cell-template
    16. let-row="row"
    17. let-i="rowIndex"
    18. >
    19. <abp-grid-actions
    20. [index]="i"
    21. [record]="row"
    22. text="AbpUi::Actions"
    23. ></abp-grid-actions>
    24. </ng-template>
    25. </ngx-datatable-column>
    26. <!-- a basic column -->
    27. <ngx-datatable-column
    28. prop="someProp"
    29. [name]="'::SomeProp' | abpLocalization"
    30. [width]="200"
    31. ></ngx-datatable-column>
    32. <!-- a column with a custom template -->
    33. <ngx-datatable-column
    34. prop="someOtherProp"
    35. [name]="'::SomeOtherProp' | abpLocalization"
    36. [width]="250"
    37. >
    38. <ng-template
    39. ngx-datatable-cell-template
    40. let-row="row"
    41. let-i="index"
    42. >
    43. <div abpEllipsis>{{ row.someOtherProp }}</div>
    44. </ng-template>
    45. </ngx-datatable-column>
    46. </ngx-datatable>

    如何迁移?

    • 安装 @swimlane/ngx-datatable 包.
    • 添加ngx-datatable样式到angular.json文件.
    • 如果可以的话,根据上面的例子更新你的模.
    • 如果你稍后需要这样做,并且打算保留abp-table一段时间,请确保根据此处描述的破坏性更改更新分页.

    **重要说明:**abp-table没有被删除,但已被弃用并在以后的版本中删除. 请考虑切换到ngx-datatable.

    扩展系统[商业版]

    扩展程序系统现在是开源的, 可以从 @abp/ng.theme.shared/extensions 而不是从 @volo/abp.commercial.ng.ui 中获取. 同样,根据config软件包的新结构,如上所述通过 forLazy 静态方法进行配置.

    如何迁移?

    如果你以前从未使用过扩展系统,则无需执行任何操作. 否则请再次检查文档以查看更改. 扩展系统本身的工作原理与以前相同,唯一的变化是你从中导入的包,静态方法以及您将贡献者传递给的模块.

    在ABP v2.x中,Lepton每个颜色主题都有一个亮徽标和一个暗徽标. 我们意识到我们可以使它仅使用一个浅色和一个深色徽标. 因此我们更改了Lepton查找徽标图像的方式,现在你只需要在项目中包含 logo-light.pnglogo-dark.png.

    如何迁移?

    如果你之前已切换模板徽标PNG,则更改很简单:

    • 转到 /assets/images/logo 目录.
    • 重命名 theme1.pnglogo-light.png 并且重命名 theme1-reverse.pnglogo-dark.png.

    如果你更换了徽标组件,则更改有些不同,但仍然很简单. LayoutStateService 有两个新成员: primaryLogoColorsecondaryLogoColor. 它们有 'light''dark' 设置值做为可观察流. 你可以使用 async 管道在自定义徽标组件模板中使用它们的值. 这是一个完整的示例,其中涵盖了主要和辅助(帐户)布局徽标.

    只要将 APP_LOGO_PROVIDER 添加到根模块的提供程序(通常是 ),你就会有一个调整主题颜色的自定义徽标组件.

    过时的接口

    某些接口早已被标记为已弃用,现在已将其删除.

    如何迁移?

    请检查你是否仍在使用Issue中列出的任何内容.

    下一步是什么?