Angular独立组件介绍

Angular 14 引入了独立组件——该组件不属于任何 ngModule 的一部分,可以与其他独立或基于模块的组件一起使用。

从 Angular 14 开始,您可以创建整个应用程序,而无需制作任何自定义 Angular 模块,这可以通过使用独立组件来实现,这些组件提供了创建 Angular 应用程序的简化方法。

1
2
3
4
5
6
7
8
9
10
11
12
13

@Compnent(
{
selector: 'app-inventory',
standalone: true,
imports: [CommonModule],
templateUrl: './inventory.component.html',
styleUrls: ['./inventory.component.html']
}
)

export class InventoryComponent implements OnInit, OnChanges {

1. 什么是独立组件

独立组件是一种不属于任何 Angular 模块的组件。在 Angular 14 之前,通常当您创建组件时,您会将其传递到模块的声明数组中。如果你不这样做,Angular 就会报错并且无法编译。但是从 Angular 14 开始,您可以创建一个不属于任何 ngModule 的组件,该组件称为独立组件。

除了独立组件之外,在 Angular 14 中,您还可以创建:

  • 独立指令
  • 独立管道

您联合独立组件与以下组件一起使用:

  • 基于模块的组件
  • 其他独立组件
  • 加载路由
  • 延迟加载

独立管道如下所示:

1
2
3
4
5
6
7
8
9
10
11
import { Pipe, PipeTransform } from "@angular/core";

@Pipe({
name: "search",
standalone: true,
})
export class SearchPipe implements PipeTransform {
transform(value: unknown, ...args: unknown[]): unknown {
return null;
}
}

2. 创建独立组件

您可以使用ng generated component --standalone 命令中的标志创建独立组件、管道或指令:

1
2
3
4
5

ng g p search --standalone
ng g d credit-card --standalone
ng g c login --standalone

独立组件能否使 Angular 14 成为 Angular 历史上最大的升级?Alyssa Nicoll 认为是这样的.

成功运行上述最后一个命令后,您可以找到添加到应用程序中的登录组件,如下所示。在这里您会注意到组件装饰器的 standalone 属性为 true。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { Component, OnInit } from "@angular/core";
import { CommonModule } from "@angular/common";

@Component({
selector: "app-login",
standalone: true,
imports: [CommonModule],
templateUrl: "./login.component.html",
styleUrls: ["./login.component.css"],
})
export class LoginComponent implements OnInit {
constructor() {}

ngOnInit(): void {}
}

独立组件、指令或管道不需要成为任何 ngModule 的一部分。如果您错误地尝试向模块添加独立组件,Angular 会抛出如下所示的错误.

1
2
3
Component LoginComponent is standalone, and cannot be declared
in an NgModule. Did you mean to import it instead? (-996008)
LoginComponent

您还可以通过将现有组件的 standalone 属性设置为 true, 将其转换为独立组件。将基于模块的组件转换为独立组件时,必须牢记以下三点:

  1. 将独立属性设置为 true。
  2. 将其从其所属模块的声明数组中删除。
  3. 使用导入数组添加依赖项。

3. 独立组件中的依赖关系

独立组件可能依赖于其他成员、管道和指令。这些依赖可以分为两部分:

  • 其他独立组件
  • 其他模块中的组件

两种类型的依赖项都可以使用 imports 装饰器数组添加到独立组件中@Component。例如,ReactiveFormsModule 可以通过 imports 添加到 LoginComponent,如下所示

1
2
3
4
5
6
7
8
@Component({
selector: 'app-login',
standalone: true,
imports: [CommonModule, ReactiveFormsModule, UserComponent],
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {

说明 UserComponent 是一个独立组件

4. 使用独立组件

您可以通过以下两种方式之一使用独立组件、指令或管道:

  • 在另一个独立组件内
  • 模块内部

要在属于 AppModule 一部分的 AppComponent 中使用它,您可以将其传递给导入数组,如下所示:

1
2
3
4
5
6
7
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, AppRoutingModule, LoginComponent],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}

现在您可以在 AppComponent 上使用它,如下所示:

1
2
3
<h1>App</h1>

<app-login></app-login>

可以通过将独立组件传递给 imports 属性来在另一个独立组件中使用该独立组件,如下所示:

1
2
3
4
5
6
7
8
@Component({
selector: 'app-product',
standalone: true,
imports: [CommonModule, LoginComponent],
templateUrl: './product.component.html',
styleUrls: ['./product.component.css']
})
export class ProductComponent implements OnInit {

5. 独立组件引导应用程序

Angular 14 允许您使用独立组件引导整个应用程序。要使用独立组件引导应用程序,请按照以下步骤操作。

在 main.ts 中,导入要引导的独立组件并 bootstrapapplication 运行,如下所示:

1
2
import { bootstrapApplication } from "@angular/platform-browser";
import { ProductComponent } from "./app/product/product.component";

之后,调用 bootstrapapplication 并传递其中的组件,如下所示:

1
2
3
bootstrapApplication(ProductComponent, {
providers: [],
});

接下来,在 index.html 上,替换 app-root 为您的组件。

1
2
3
4
<body>
<!-- <app-root></app-root> -->
<app-product></app-product>
</body>

现在,当您运行应用程序时,应用程序应该从 ProductComponent 引导

6. 使用独立组件进行路由

企业级应用程序必须具有各种路由,以便用户可以通过更改 URL 来导航不同的组件。因此,为了支持此功能,还可以使用独立组件来创建路由并进行延迟加载。

  • 可以使用独立组件创建路由。
  • 在创建类似模块的路由时,独立组件也可以延迟加载。
  • 子路由也可以与所有路由组件一起作为独立的延迟加载。
  • 单独的注入器可以传递到独立的组件路由。

假设您已使用独立的 AppComponent 引导应用程序并将其添加<router-outlet></router-outlet>到模板中,以便可以在此处加载不同的路由。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { CommonModule } from "@angular/common";
import { Component } from "@angular/core";
import { RouterModule } from "@angular/router";

const template = `
<h1>{{title}}</h1>
<router-outlet></router-outlet>
`;
@Component({
selector: "app-root",
standalone: true,
imports: [CommonModule, RouterModule],
template: template,
styleUrls: ["./app.component.css"],
})
export class AppComponent {
title = "Stand alone component App";
}

7. 添加路由

现在,要创建路由,请添加一个文件并根据需要命名。我给它起了名字 app-routing.ts。在此文件中,配置导航到 Home 组件的路由,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { Routes } from "@angular/router";
import { HomeComponent } from "./home/home.component";

export const APP_ROUTES: Routes = [
{
path: "",
pathMatch: "full",
redirectTo: "home",
},
{
path: "home",
component: HomeComponent,
},
];

添加路由后,使用独立的 AppComponent 引导应用程序。为此,在 main.ts 中,导入 AppComponent、RouterModule、App_Routes 和 bootstrapapplication 函数,如下所示

1
2
3
4
5
6
import { enableProdMode, importProvidersFrom, inject } from "@angular/core";
import { bootstrapApplication } from "@angular/platform-browser";
import { environment } from "./environments/environment";
import { AppComponent } from "./app/app.component";
import { RouterModule } from "@angular/router";
import { APP_ROUTES } from "./app/app-routing";

之后,调用 bootstrapapplication 并传递其中的组件,如下所示:

1
2
3
bootstrapApplication(AppComponent, {
providers: [importProvidersFrom(RouterModule.forRoot(APP_ROUTES))],
});

独立组件引导操作可能有许多依赖项,必须在 providers 数组中显式传递这些依赖项。其中一些依赖项可能是 ngModules 的一部分,因此可能需要该模块来配置依赖项注入。

此类示例之一是 RouterModule.forRoot()设置应用程序路由的依赖关系。为了进行设置,Angular 提供了一个实用程序 importProvidersFrom。这里该实用程序用于注入应用程序路由器依赖项:

1
2
3
bootstrapApplication(AppComponent, {
providers: [importProvidersFrom(RouterModule.forRoot(APP_ROUTES))],
});

运行应用程序时,您应该导航主路径并进行 HomeComponent 加载

到目前为止,您已经成功:

使用独立组件引导应用程序
配置并添加路由

8. 延迟加载独立组件

与模块一样,独立组件也可以延迟加载。loadComponent 您可以通过使用该语句并传递组件文件名来延迟加载路由中的独立组件。

1
2
3
4
5
6
7

{
path: 'product',
loadComponent: () => import('./product/product.component')
.then(m => m.ProductComponent)
}

您可以通过修改应用程序路由来添加带有延迟加载组件的产品路由:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
export const APP_ROUTES: Routes = [
{
path: "",
pathMatch: "full",
redirectTo: "home",
},
{
path: "home",
component: HomeComponent,
},
{
path: "product",
loadComponent: () =>
import("./product/product.component").then((m) => m.ProductComponent),
},
{
path: "**",
component: PagenotfoundComponent,
},
];

如您所见,添加了一个新的路由产品,并且它正在使用 loadComponent()带有 import 语句的函数。

运行应用程序时,您会发现 ProductComponent 在导航产品路线时会延迟加载

9. 延迟加载多个子路由

Angular 14 还延迟加载具有多个独立组件的子路由。

在路由文件中使用独立组件配置子路由,如下所示

1
2
3
4
5
6
7
8
9
10
export const ADMIN_ROUTES: Route[] = [
{
path: "",
pathMatch: "full",
redirectTo: "home",
},
{ path: "home", component: AdminhomeComponent },
{ path: "users", component: AdminduserComponent },
{ path: "dashboard", component: AdmindashboardComponent },
];

当所有路由组件都是独立的时,您可以使用 loadChildren 带有 import 的方法来延迟加载子路由。这里上面的路由配置放在 admin.route 文件中。

1
2
3
4
{
path: 'admin', loadChildren: () => import('./admin/admin.route')
.then(mod => mod.ADMIN_ROUTES)
}

将所有内容与延迟加载的组件和子路由放在一起,应用程序路由应如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
export const APP_ROUTES: Routes = [
{
path: "",
pathMatch: "full",
redirectTo: "home",
},
{
path: "home",
component: HomeComponent,
},
{
path: "product",
loadComponent: () =>
import("./product/product.component").then((m) => m.ProductComponent),
},
{
path: "admin",
loadChildren: () =>
import("./admin/admin.route").then((mod) => mod.ADMIN_ROUTES),
},
{
path: "**",
component: PagenotfoundComponent,
},
];

运行应用程序时,您会发现导航管理路由时会延迟加载管理子路由。

10. 配置依赖注入

在使用独立组件引导应用程序时,您还可以注入应用程序的依赖项,如下所示:

1
2
3
4
5
6
7
bootstrapApplication(AppComponent, {
providers: [
{ provide: AppService, useClass: AppService },
{ provide: BACKEND_URL, useValue: "abc.com" },
importProvidersFrom(RouterModule.forRoot(APP_ROUTES)),
],
});

11. Angular 系列文章

最新更新以及更多 Angular 相关文章请访问 Angular 合集 | 鹏叔的技术博客

12. 总结

因此,如您所见,使用独立组件非常简单。如果您要创建新的 Angular 项目,请从 Angular 14 开始,并尝试使用独立组件引导应用程序。

13. 参考文章

A guide to Standalone Components in Angular