NgModules 将组件、指令和管道整合到有凝聚力的功能块中,每个功能块都专注于一个功能区域、应用程序业务域、工作流或实用程序的公共集合。
NgModule 是由 @NgModule 装饰器标记的类。 @NgModule 接受一个元数据对象,该对象描述如何编译组件的模板以及如何在运行时创建注入器。它通过exports 属性识别模块自己的组件、指令和管道,将其中一些公开,以便外部组件可以使用它们。 @NgModule 还可以将服务提供者添加到应用程序依赖注入器。
Angular 14 将引入另一种编写应用程序的方法——独立组件、指令和管道。
术语“独立”是指可以独立于 NgModule 使用的组件、指令或管道。尽管您仍然需要使用核心和外部 NgModule,但您可能不需要创建新的。
让我们创建一个没有 NgModules 的应用程序。首先,我们需要使用 angular-cli 生成它:
npx @angular/cli@next new ng14
下一步是删除 app.module.ts 并将 main.ts 中的 bootstrapModule() 函数替换为 bootstrapApplication():
import { enableProdMode } from '@angular/core'; import { bootstrapApplication } from '@angular/platform-browser'; import { AppComponent } from './app/app.component'; import { environment } from './environments/environment'; if (environment.production) { enableProdMode(); } bootstrapApplication(AppComponent)
bootstrapApplication() 可以获取根组件及其所有子组件应该可用的提供程序列表:
import { importProvidersFrom } from '@angular/core'; import { bootstrapApplication } from '@angular/platform-browser'; import { AppComponent } from './app/app.component'; import { HttpClientModule } from '@angular/common/http' bootstrapApplication(AppComponent, { providers: [importProvidersFrom(HttpClientModule)] }).catch(err => console.error(err));
该函数从提供的模块中提取提供者。
现在我们需要将 AppComponent 更改为独立组件。让我们将独立属性设置为true :
@Component({ selector: 'app-root', templateUrl: './app.component.html', standalone: true, styleUrls: ['./app.component.scss'] }) export class AppComponent {}
现在我们可以在浏览器中看到 AppComponent 的模板。由于我们的组件是独立的,我们可以使用新的 imports 属性。 imports 属性指定组件的模板依赖项——它可以使用的那些指令、组件和管道。
独立组件可以导入其他独立组件、指令、管道和现有的 NgModules。例如,我们可以创建一个独立的指令,并在我们的组件中使用它:
npx ng g directive foo --standalone
import { Directive } from '@angular/core'; @Directive({ selector: '[appFoo]', standalone: true }) export class FooDirective {}
import { CommonModule } from '@angular/common'; import { FooDirective } from './foo.directive'; @Component({ selector: 'app-root', template: ` <div appFoo *ngIf="bar">Foo</div> `, standalone: true, imports: [FooDirective, CommonModule] }) export class AppComponent {}
让我们向应用程序添加路由。
const routes: Routes = [{ path: 'todos', component: TodosPageComponent }] @Component({ selector: 'app-root', template: ` <a routerLink="/todos">Todos</a> <router-outlet></router-outlet> `, standalone: true, imports: [RouterModule.forRoot(routes)], styleUrls: ['./app.component.scss'] }) export class AppComponent {}
这是不可能的,因为 Angular 不允许我们在独立组件中使用 ModuleWithProvider。接下来,我们可能会尝试在组件的提供程序中使用新的 importProvidersFrom 函数:
const routes: Routes = [{ path: 'todos', component: TodosPageComponent }] @Component({ selector: 'app-root', template: ` <a routerLink="/todos">Todos</a> <router-outlet></router-outlet> `, standalone: true, providers: importProvidersFrom(RouterModule.forRoot(routes)), imports: [FooDirective, CommonModule], styleUrls: ['./app.component.scss'] }) export class AppComponent {}
使用应用内导航将起作用。路由器将错过第一次导航。路由器的初始化应该在引导过程中执行:
bootstrapApplication(AppComponent, { providers: [importProvidersFrom(RouterModule.forRoot(routes))] }).catch(err => console.error(err));
TodosPageComponent 被急切地加载。让我们将其更改为延迟加载并添加一个 TodoPageComponent:
import { Routes } from '@angular/router'; export const todosRoutes: Routes = [ { path: 'todos', title: 'Todos Page', children: [ { path: '', loadComponent: () => import('./todos-page.component').then((m) => m.TodosPageComponent), children: [ { path: ':id', loadComponent: () => import('./todo-page/todo-page.component').then( (m) => m.TodoPageComponent ), }, ], }, ], }, ];
我们不使用 loadChildren 并传递 NgModule,而是使用 loadComponent 属性并传递一个组件。我们还可以使用新的 providers 属性为这条 Route 及其子节点声明提供者:
import { Routes } from '@angular/router'; export const todosRoutes: Routes = [ { path: 'todos', title: 'Todos Page', providers: [ { provide: 'Angular', useValue: 'v14', }, ], children: [ { path: '', loadComponent: () => import('./todos-page.component').then((m) => m.TodosPageComponent), children: [ { path: ':id', loadComponent: () => import('./todo-page/todo-page.component').then( (m) => m.TodoPageComponent ), }, ], }, ], }, ];
我们还可以将一组路由传递给 loadChildren:
export const ROUTES: Route[] = [ { path: 'child', component: ChildCmp}, ]
{ path: 'parent', loadChildren: () => import('./children').then(m => m.ROUTES), }
结论:
未来几天,Angular 团队可能会推出 Angular 14 更新和新功能。敬请关注!
原文: https://dev.to/pranambhat/say-no-to-ngmodule-in-angular-14-39hl