angular开源代码_将Angular NgModules用于可重用代码等

angular开源代码

NgModules是Angular的核心概念,它是每个应用程序的一部分,有助于为编译器和应用程序运行时连接一些重要的细节。 它们对于将代码组织成功能,延迟加载路由以及创建可重用的库特别有用。

在本指南中,我们将通过一些示例介绍NgModules的主要用法,向您展示如何在Angular项目中使用它们! 本指南假定您具有Angular的使用知识。

JavaScript模块不是NgModules

首先,让我们澄清一下什么是JavaScript模块(有时称为ES6模块)。 它们是一种语言构造,可以更轻松地组织代码。

最基本的Javascript模块是包含importexport关键字JavaScript文件,这些文件会导致在该文件内定义的对象是私有的,除非您将其导出。 我鼓励您查看上面的链接以加深了解,但是从本质上讲,这是一种组织代码并轻松共享代码的方法,而无需依赖可怕的全局范围。

当您使用TypeScript创建Angular应用程序时,每次在源中使用importexport ,都会将其视为JavaScript模块。 TypeScript能够为您处理模块加载。

注意:为了使本文更清楚明了,我将始终使用全名来引用JavaScript模块和NgModules。

基本的NgModule,AppModule

让我们从每个Angular应用程序中存在的基本NgModule开始,即AppModule (在任何新的Angular应用程序中默认生成)。 看起来就像您在这里看到的那样:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Angular使用修饰符来定义在编译期间需要了解的元数据。 要定义NgModue,只需在类上方添加@NgModule()装饰器。 该类可能并不总是空的,但通常是空的。 但是,您需要为NgModule定义具有一些属性的对象才能执行任何操作。

当应用程序启动时,需要给它一个NgModule进行实例化。 如果查看应用程序的主文件(通常也称为main.ts ),则会看到platformBrowserDynamic().bootstrapModule(AppModule) ,这是应用程序注册和启动AppModule (可以命名为任意名称,但是几乎总是以此命名)。

NgModule的属性

NgModule API文档页面概述了定义NgModule时可以传递的属性,但我们也会在此处进行介绍。 它们都是可选的,但是您需要为NgModule定义其中至少一个的值才能执行任何操作。

providers

providers是一个数组,其中包含可用于此NgModule的所有提供程序 (可注入服务)的列表。 提供者具有作用域,并且如果它们在延迟加载的NgModule中列出,则在该NgModule之外不可用。

declarations

declarations数组应包含此NgModule定义的所有指令,组件或管道的列表。 这使编译器可以找到这些项目并确保将它们正确捆绑在一起。 如果这是根NgModule,则声明可用于所有NgModule。 否则,它们仅对同一NgModule可见。

imports

如果您的NgModule依赖于另一个NgModule的任何其他对象,则必须将其添加到imports数组。 这样可以确保编译器和依赖项注入系统了解导入的项目。

exports

使用exports数组,您可以定义哪些指令,组件和管道可用于导入此NgModule的任何NgModule。 例如,在UI库中,您将导出组成该库的所有组件。

entryComponents

任何需要在运行时加载的组件都必须添加到entryComponents列表中。 本质上,这将创建组件工厂并在需要动态加载时存储它。 您可以从文档中了解有关如何动态加载组件的更多信息。

bootstrap

您可以定义任意数量的组件,以便在首次加载应用程序时进行引导。 通常,您只需要引导主根组件(通常称为AppComponent ),但是如果您有多个根组件,则将在此处声明每个根组件。 通过将组件添加到bootstrap数组,它也被添加到entryComponents列表中并进行了预编译。

schemas

模式是定义Angular编译模板的方式,并且当它发现不是标准HTML或已知组件的元素时是否会抛出错误。 默认情况下,Angular在模板中找不到未知元素时会引发错误,但是您可以通过将架构设置为NO_ERRORS_SCHEMA (允许所有元素和属性)或CUSTOM_ELEMENTS_SCHEMA (允许任何元素)来更改此行为或名称中带有-属性)。

id

此属性使您可以为NgModule提供唯一的ID,该ID可用于检索模块工厂引用。 目前,这是一种罕见的用例。

NgModule示例

为了说明NgModule与Angular结合使用的方式,让我们看一组示例,这些示例向您展示如何轻松处理各种用例。

功能NgModules

免费学习PHP!

全面介绍PHP和MySQL,从而实现服务器端编程的飞跃。

原价$ 11.95 您的完全免费

除了AppModule之外, AppModule最基本用例是功能NgModules (通常称为功能模块,但试图保持术语一致)。 它们有助于将应用程序的各个部分分开,因此强烈建议使用。 在大多数情况下,它们与主应用程序NgModule相同。 让我们看一下基本的功能NgModule:

@NgModule({
  declarations: [
    ForumComponent,
    ForumsComponent,
    ThreadComponent,
    ThreadsComponent
  ],
  imports: [
    CommonModule,
    FormsModule,
  ],
  exports: [
    ForumsComponent
  ]
  providers: [
    ForumsService
  ]
})
export class ForumsModule { }

这个简单的功能NgModule定义了四个组件,一个提供程序,并导入了组件和服务所需的两个模块。 这些共同构成了应用程序论坛部分的必要部分。

providers中的项目可用于任何导入要注入的ForumsModule ,但是了解每个NgModule将获得自己的服务实例非常重要。 这与根NgModule中列出的提供程序不同,从该提供程序中您将始终获得相同的实例(除非重新提供了该实例)。 在这里,重要的是要理解依赖注入,尤其是层次依赖注入 。 很容易想到您将获得服务的相同实例并更改其属性,但从未在应用程序的其他位置看到更改。

如我们先前所知, declarations中的项目实际上不可用于其他NgModule,因为它们是此NgModule专用的。 要解决此问题,您可以选择导出要在其他NgModule中使用的那些声明,例如在此代码段中仅导出ForumsComponent 。 现在,在任何其他功能NgModule中,您可以放置<app-forums></app-forums> (或该组件的任何选择器)以在模板中显示ForumsComponent

另一个主要区别是ForumsModule导入CommonModule而不是BrowserModuleBrowserModule仅应在根NgModule处导入,但CommonModule包含核心的Angular指令和管道(例如NgForDate管道)。 如果您的Feature NgModule不使用任何这些功能,则实际上并不需要CommonModule

现在,当您想在项目中使用ForumsModule时,需要像在此处看到的那样将其导入到AppModule

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    ForumsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

然后,将此NgModule导入到主AppModule以正确加载它,其中包括ForumsModule提供程序数组中的项目以及任何导出的项目,供您在应用程序中使用。

使用Angular CLI时,可以通过为新的NgModule运行生成器来轻松生成Feature NgModule:

ng generate module path/to/module/feature

您可以按照自己认为合适的任何方式组织Feature NgModule,但是通常的建议是将用于同一视图的相似内容归为一组。 我尝试制作少量的Feature NgModules来保存常用的东西,然后针对应用程序的每个主要功能,将更多的精力放在NgModules上。

用路由延迟加载NgModules

有时,您只想在用户需要时才加载代码,而通过Angular,当前可以通过将路由器和Feature NgModules一起使用来加载代码。 当用户请求特定路由时,路由器可以延迟加载NgModule。 如果您不熟悉路由,请参阅有关使用Angular进行路由的入门

最好的开始方法是为路由的唯一部分创建功能NgModule。 如果它们几乎总是一起使用,您甚至可能希望将多个路由组合在一起。 例如,如果您有一个客户帐户页面,其中包含几个用于管理帐户详细信息的子页面,则很有可能将它们声明为同一NgModule的一部分。

定义NgModule本身的方式没有什么区别,只不过需要使用RouterModule.forChild()定义一些路由。 您应该有一个路径为空的路由,该路由的作用类似于此Feature NgModule的根路由,所有其他路由都将挂起:

@NgModule({
  declarations: [
    ForumComponent,
    ForumsComponent,
  ],
  imports: [
    CommonModule,
    FormsModule,
    RouterModule.forChild([
      {path: '', component: ForumsComponent},
      {path: ':forum_id', component: ForumComponent}
    ])
  ],
  providers: [
    ForumsService
  ]
})
export class ForumsModule { }

行为上有一个重要变化,与提供者在应用程序中的注册方式无关。 由于这是一个延迟加载的NgModule,因此提供程序对其余应用程序不可用 。 这是一个重要的区别,在规划应用程序体系结构时应考虑到这一点。 在这里,了解Angular 依赖注入的工作原理非常重要。

要加载延迟路由,主AppModule定义了前往该功能NgModule的路径。 为此,您必须为新路由更新根路由器配置。 此示例显示了如何通过为其指定pathloadChildren属性来定义延迟加载的路由:

const routes: Routes = [
  {
    path: 'forums',
    loadChildren: 'app/forums/forums.module#ForumsModule'
  },
  {
    path: '',
    component: HomeComponent
  }
];

loadChildren属性的语法是一个字符串,该字符串具有NgModule文件的路径(不带文件扩展名), #符号以及NgModule类的名称: loadChildren: 'path/to/module#ModuleName 。 Angular使用它来知道在运行时在哪里加载文件,并知道NgModule的名称。

延迟加载的路由的路径是在路由的根级别定义的,因此延迟加载的NgModule甚至都不知道其路由的路径。 这使它们更具可重用性,并使应用程序知道何时延迟加载该NgModule。 考虑将所有路由定义为相对路径的延迟加载NgModule,通过组合根路由和延迟加载路由来提供完整路径。

例如,如果您访问/路线在此应用中,它会载入HomeComponentForumsModule不会被加载。 但是,一旦用户单击链接查看论坛,就会注意到/forums路径要求加载ForumsModule ,然后下载并从中注册定义的路由。

路由NgModule

Angular的常见模式是使用单独的NgModule承载所有路由。 这样做是为了分离关注点,并且完全是可选的。 当您通过传递--routing标志创建新模块时,Angular CLI支持自动生成路由NgModule:

ng generate module path/to/module/feature --routing

发生的情况是,您创建了一个独立的NgModule来定义您的路线,然后功能NgModule导入了它。 路由NgModule可能如下所示:

const routes: Routes = [
  { path: '', component: ForumsComponent }
];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class ForumsRoutingModule { }

然后将其导入到您的ForumsModule如下所示:

@NgModule({
  declarations: [
    ForumComponent,
    ForumsComponent,
  ],
  imports: [
    CommonModule,
    FormsModule,
    ForumsRoutingModule,
  ],
  providers: [
    ForumsService
  ]
})
export class ForumsModule { }

这在很大程度上是首选项,但这是您应该考虑的常见模式。 本质上,这是使用NgModules进行代码分离的另一种方法。

单身人士服务

我们已经看到了一些有关提供程序的问题,除非您仅在根NgModule中提供服务,否则无法保证在NgModules中获得相同的服务实例。 有一种方法可以定义NgModule,以便它只能为根NgModule声明提供程序,而不为所有其他NgModule声明它们。

实际上,Angular路由器就是一个很好的例子。 在根NgModule中定义路由时,可以使用RouterModule.forRoot(routes) ,而在功能NgModule内部,可以使用RouterModule.forChild(routes) 。 对于需要单个服务实例(单例)的可重用库,此模式很常见。 我们可以通过向NgModule中添加两个静态方法来对任何NgModule进行相同操作,如您在此处看到的:

@NgModule({
  declarations: [
    ForumComponent,
    ForumsComponent,
    ThreadComponent,
    ThreadsComponent
  ],
  imports: [
    CommonModule,
    FormsModule,
  ],
  exports: [
    ForumsComponent
  ]
})
export class ForumsModule {
  static forRoot(): ModuleWithProviders {
    return {
      ngModule: ForumsModule,
      providers: [ForumsService]
    };
  }

  static forChild(): ModuleWithProviders {
    return {
      ngModule: ForumsModule,
      providers: []
    };
  }
}

然后在我们的AppModule ,使用forRoot()方法定义导入,该方法将返回带有提供程序的NgModule。 在导入ForumsModule任何其他NgModule中,您将使用forChild()方法,因此您无需再次声明提供程序(从而创建一个新实例):

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    ForumsModule.forRoot()
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

NgModules用于分组NgModules

您可以将多个其他NgModule组合为一个,以使其更易于导入和重用。 例如,在我从事的Clarity项目中,我们有许多NgModules仅导出其他NgModules。 例如,这是主要的ClarityModule ,它实际上是重新导出包含每个组件的其他各个NgModule:

@NgModule({
  exports: [
    ClrEmphasisModule, ClrDataModule, ClrIconModule, ClrModalModule, ClrLoadingModule, ClrIfExpandModule, ClrConditionalModule, ClrFocusTrapModule, ClrButtonModule, ClrCodeModule, ClrFormsModule, ClrLayoutModule, ClrPopoverModule, ClrWizardModule
  ]
})
export class ClarityModule { }

这使一次导入多个NgModule变得容易,但是,这确实使编译器更难知道哪些NgModule用于树摇优化。

摘要

我们在Angular中进行了NgModules的旋风之旅,并介绍了关键用例。 关于NgModules的Angular文档也很深入,如果您遇到困难,建议您查阅FAQ

翻译自: https://www.sitepoint.com/angular-ngmodules/

angular开源代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值