Angular NgModule 作用域相关问题
NgModule 是你使用 Angular 编写应用程序时遇到的第一个基本结构,但由于涉及不同的作用域范围,它也是最微妙和最复杂的。如果你想详细了解 NgModule 的相关知识,可以直接参考 Angualr NgModule FAQ 或 Angular FAQ 文章中 NgModule 版块的内容 。 Why NgModule?我们可以使用 Angular CLI,自动完成很多工作,但我们必须要做的第一件事就是加载根模块。 platformBrowserDynamic().bootstrapModule(AppModule); NgModule 的目的是声明我们在 Angular 模块中创建的内容,主要有以下两种结构:
import { NgModule } from '@angular/core'; import { SomeComponent } from './some.component'; import { SomeDirective } from './some.directive'; import { SomePipe } from './some.pipe'; import { SomeService } from './shared/some.service'; @NgModule({ declarations: [SomeComponent,SomeDirective,SomePipe],providers: [SomeService] }) export class SomeModule {} NgModule 是 Angular RC 阶段新增的一个功能,因为 ES 6 中已经新增 import/export 功能,在引入 NgModule 似乎增加了不必要的复杂性。但引入了 NgModule 让我们可以使用 NgModule and scopes/visibility
这意味着你声明的组件只能在当前模块中使用。如果你想要在外面使用声明的组件,你必须导出它们: import { NgModule } from '@angular/core'; import { SomeComponent } from './some.component'; import { SomeDirective } from './some.directive'; import { SomePipe } from './some.pipe'; @NgModule({ declarations: [SomeComponent,exports: [SomeComponent,SomePipe] }) export class SomeModule {} 反之,模块中的声明的服务,我们可以在所有模块中使用。 When to import a NgModule?components 和 services 拥有不同的作用域,了解这个区别很重要。如果我们的应用程序不仅仅包含一个模块,事情可能会变得很糟糕。Angular 框架内部也拆分成多个不同的模块,如 core、common、http 等等。 在 Angular 模块中我们需要做的一件主要的事情是导入其它模块: import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { HttpModule } from '@angular/http'; import { FeatureModule } from '../feature/feature.module'; @NgModule({ imports: [CommonModule,HttpModule,FeatureModule] }) export class SomeModule {} 现在的主要问题是,你必须知道为什么需要导入这些模块:
因为组件和服务,拥有不同的作用域:
如果你不了解这些区别,你可能由于忘记导入某个模块,而出现组件不可用的错误。或者你为了使用某个模块中定义的服务,而多次导入同一个模块。 When to import main Angular Modules?Modules to import each time you need them
Modules to import only once
The ShareModule good practice若使用 Angular CLI 创建新的模块,它会自动帮我们导入 管理 SharedModule 时,需要很小心。如果你只是导入模块,它将无法正常工作: import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { FlexLayoutModule } from '@angular/flex-layout'; import { MaterialModule } from '@angular/material'; @NgModule({ imports: [CommonModule,FlexLayoutModule,MaterialModule] }) export class SharedModule {} 为什么呢?原因仍是作用域的问题:组件只在 SharedModule 中可用,在其它导入 SharedModule 的模块中,仍然是不可用的。因此我们需要导出相应的组件: import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { FlexLayoutModule } from '@angular/flex-layout'; import { MaterialModule } from '@angular/material'; @NgModule({ imports: [CommonModule,MaterialModule],exports: [CommonModule,MaterialModule] }) export class SharedModule {} 如果我们组件不包含其它共享的资源,我们可以省略 imports 属性: import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { FlexLayoutModule } from '@angular/flex-layout'; import { MaterialModule } from '@angular/material'; @NgModule({ exports: [CommonModule,MaterialModule] }) export class SharedModule {} Mixed NgModule如何同时管理具有组件和服务的模块?这是一个比较复杂的问题。你可能已经接触过 RouterModule,该模块不仅提供了 幸运的是,这个问题是由模块本身来解决。 Angular CLI 会为我们自动生成路由文件,但你可能已经注意到,应用程序主模块的路由和子模块路由之间存在细微差别。 对于 AppModule,我们这样使用: RouterModule.forRoot(routes) 对于子模块,我们这样使用: RouterModule.forChild(routes) 为什么呢?因为在 AppModule 中,forRoot() 方法会导入路由模块中的指令和服务。但对于子模块来说,forChild() 方法仅会导入路由模块中定义的指令,而不会再次导入模块中定义的服务。 Lazy-loaded modules如果你需要实现模块懒加载,可以简单地使用 Angular CLI 来实现: const routes: Routes = [ { path: 'admin',loadChildren: './admin/admin.module#AdminModule' } ]; 因为它将是一个不同的包和模块,默认情况下是按需加载,它不会包含在您的应用程序的全局范围内。 对于组件来说,你不需要更改任何内容:就像在任何子模块中一样,你需要再次导入 CommonModule 或 SharedModule 模块。 但对于服务来说,有一些区别:
参考资源
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |