0
点赞
收藏
分享

微信扫一扫

模块化开发 Angular 应用 [含懒加载]

想要更好地理解 ​​Angular​​ 应用程序所有的不同构建的模块?

在这篇文章中,我们将走进模块的内容。

在 ​​angular​​ 应用中,模块是共享和重用代码的好方法。

共享模块不仅让你的应用联系紧密,而且可以对你的应用进行瘦身。

在这个教程中,我们将创建自定义的模块,并发掘它的组件。

然后,我们将学习怎么使用我们的模块来启用延迟加载,从而使应用更小,使用户体验更好。

我们开始吧!

模块化开发 Angular 应用 [含懒加载]_Angular.js

App Module

在 ​​Angular​​​ 里面,一切皆可组织成模块。所以,即使你不知道哪些是模块或者怎么使用它们,你已经无行在应用中使用它们了。其中最突出的是 ​​AppModule​​。

​AppModule​​​ 是你应用中的根模块,并且对于运行我们的应用程序是必要的模块。在这里,我们可以定义应用程序使用哪些组件或者哪些模块。那么它长什么样呢?我们通过 ​​angular-cli​​​ 来生成一个基本的 ​​AppModule​​。

// src/app/app.module.ts

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

要生成你自己的模块,请打开终端并进入项目的根目录。

使用下面的命令行去生成一个新的模块文件。

ng generate module [name]

模块化开发 Angular 应用 [含懒加载]_Angular.js_02

一个 Angular Module 是什么?

简单来说,一个模块就是一个类,就像组件和服务一样。

​Angular​​ 中的代码通常以模块的形式组织。我们可以将模块视为包含特定用例所需要代码的包或捆绑包。

最重要的模块是 ​​App-Module​​,每个通过脚手架生成的应用都有它。

但是,​​App-Module​​ 很可能不是你目前为止遇到的唯一模块。还有很多开箱即用的模块。

比如 ​​Http-Client-Module​​​,它包含一个很有用处的 ​​Http-Client​​​ 和 ​​Forms-Module​​​(其中包含 ​​UI​​​ 组件和 ​​HTML-Forms​​ 指令)。

正如我们上面的例子中看到的,我们要使用模块之前,需要先导入模块。

​App-Module​​ 是应用程序的根模块。该模块导入其他模块,这些模块可以自己导入其他模块。

就像组件一样,生成的结构是一个模块树。

模块化开发 Angular 应用 [含懒加载]_JavaScript_03

@NgModule

在 ​​@NgModule​​​ 操作符里面,我们定义模块的所有属性。我们提供了一个简单的 ​​JavaScript​​ 对象作为参数。让我们仔细点看,这些属性是什么,又干了些什么:

Bootstrap

定义应用程序的根组件。仅在 ​​AppModule​​ 中使用它。

Exports

我们在这里定义要组件、指令或者管道。这意味着,我们的模块在导入时将这些模块提供给其他模块。否则,这些模块将停留在模块内部,无法从外部访问。

Declarations

在 ​​declarations​​​ 数组中,我们定义着所有的组件,指令和管道,我们可以在这个模块内使用。如果一个组件(或者指令或者管道)你并没有添加到 ​​declarations​​​ 中,但是你又在模块或者应用中使用了,​​angular​​ 应用在运行时报错。此外,一个组件只能在一个模块中声明。如果你想在多个模块中使用你的组件,你需要将改组件捆绑到一个单独的模块中,并将其导入到模块中

Imports

说到导入... 你的模块可以导入任意数量的子模块。还没有定义任何自定义模块?没问题,我们将解决这个问题。即使你没有任何模块,你仍然需要导入一些 ​​angular​​​ 模块。正如我们之前提到的,​​Angular​​​ 在构建之初已经考虑到了模块化。虽然很多特性都包含在 ​​Angular​​​ 的核心中,但是有些特性被捆绑在它们自己的模块中。比如,你想使用 ​​HttpClient​​​,你得想导入 ​​HttpClientModule​​。

Providers

我们定义了模块所需的任何的 ​​@Injectables​​​。然后,任何子组件或者模块都可以通过依赖注入获得该 ​​@Injectables​​​ 相同的实例。在 ​​AppModule​​​ 案例中,这些 ​​@Injectables​​​ 就是 ​​application-scoped​​。

构建自定义模块

我们假装已经构建了一个很棒的应用程序。这个程序只有一个模块,就是 ​​AppModule​​。

现在,为我们应用程序添加登录内容。登录内容将包含一个登录的页面和一个注册的页面。也许会有一个帮助的页面。每个页面都是以组件的方式呈现。

LoginComponent
RegisterComponent
HelpComponent

同时,我们需要一个服务发起 ​​Http​​ 请求。

AuthenticationService

由于这些页面是完全独立的,并且与我们应用程序的内容页面无关。我们决定将它们捆绑到一个单独的模块中。我们称这个模块为 ​​AuthentictionModule​​。

// src/app/authentication/authentication.module.ts

import { NgModule } from '@angular/core'
import { CommonModule } from '@angular/common'

@NgModule({
imports: [CommonModule],
})
export class AuthenticationModule

现在,将我们的组件添加到 ​​declarations​​​ 部分。同时,我们将它们放在 ​​exports​​ 部分,因为我们想在模块外部使用它们。

// src/app/authentication/authentication.module.ts

import { HelpComponent } from './help/help.component'
import { RegisterComponent } from './register/register.component'
import { LoginComponent } from './login/login.component'
import { NgModule } from '@angular/core'
import { CommonModule } from '@angular/common'

@NgModule({
imports: [CommonModule],
declarations: [LoginComponent, RegisterComponent, HelpComponent],
exports: [LoginComponent, RegisterComponent, HelpComponent],
})
export class AuthenticationModule

已经准备好了。现在,我们可以在 ​​AppModule​​​ 导入它,然后使用它里面的组件,比如在 ​​AppComponent​​ 中使用。

// src/app/app.module.ts

import { AuthenticationModule } from './authentication/authentication.module'
import { BrowserModule } from '@angular/platform-browser'
import { NgModule } from '@angular/core'

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

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

模块化开发 Angular 应用 [含懒加载]_Angular.js_04

Lazy-Loading Modules

事实表明,你可以使用模块做更多事情,而不是仅仅组织你的组件。也可以延迟加载模块。这是什么意思呢?

​Angular​​ 程序的下载体积很大。根据你的用户场景,这是一个很大的问题。特别是在移动端,加载一个应用程序可能需要耗费很长时间。减少加载时间的一种方法是将应用程序拆分成模块。

当你以惰性方式加载模块时,它不会包含在初始的程序中。相反,它仅在需要的时候才下载。为啥要下载我们还没用得上的组件呢,是吧?

那么,它是怎么工作的?

我们用惰性加载方式更改下先前的例子。为了实现这点,我们要在应用中添加路由。

首先,我们用路由配置来配置路由模块。所以,我们创建一个名为 ​​app.routing.ts​​​ 的文件,它跟 ​​app.module​​ 同级。

// src/app/app.routing.ts

import { ContentComponent } from './content/content.component'
import { Routes, RouterModule } from '@angular/router'
import { ModuleWithProviders } from '@angular/core'

export const routes: Routes = [
{ path: '', pathMatch: 'full', redirectTo: 'content' },
{ path: 'content', component: ContentComponent },
{
path: 'login',
loadChildren: './authentication/authentication.module#AuthenticationModule',
},
]

export const routing: ModuleWithProviders = RouterModule.forRoot(routes)

非延迟加载的组件由路径和组件属性指定。如果我们想在特定的路由上延迟加载模块,我们可以使用 ​​loadChildren​​​ 属性。这里我们指定模块的路径和名称,用 ​​#​​ 分隔开。

之后,我们可以在我们的 ​​AppModule​​​ 中导入配置模块。我们还删除了 ​​AuthenticationModule​​ 的导入,因为它是延迟加载的。

// src/app/app.module.ts

import { routing } from './app.routing'
import { BrowserModule } from '@angular/platform-browser'
import { NgModule } from '@angular/core'

import { AppComponent } from './app.component'
import { ContentComponent } from './content/content.component'

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

接着,我们在程序的某个地方添加 ​​router-outlet​​​。这里我们把它放在 ​​AppComponent​​ 中。

<!-- src/app/app.component.html -->

<router-outlet></router-outlet>

如果我们进入那个路由,那个模块将被加载。但是此时屏幕上什么都没有。因为 ​​Angular​​​ 还不知道现实哪个组件。为了解决这个问题,我们必须为 ​​authentication module​​​ 定义子路由。这看起来集合和 ​​app.routing​​​ 完全一样。不一样的是,我们调用的是 ​​forChild()​​​ 而不是 ​​forRoot()​​,当然,路由也不同。

// src/app/authentication/authentication.routing.ts

import { AuthenticationComponent } from './authentication.component'
import { HelpComponent } from './help/help.component'
import { RegisterComponent } from './register/register.component'
import { LoginComponent } from './login/login.component'
import { Routes, RouterModule } from '@angular/router'
import { ModuleWithProviders } from '@angular/core'

export const routes: Routes = [
{ path: '', component: LoginComponent }, // default route of the module
{ path: 'login', component: LoginComponent },
{ path: 'register', component: RegisterComponent },
{ path: 'help', component: HelpComponent },
]

export const routing: ModuleWithProviders = RouterModule.forChild(routes)

现在需要做的是,将路由导入到 ​​AuthenticationModule​​ 中。当我们再次进入路由后,登陆组件会被展示出来。这是因为我们配置其为默认路由。

// src/app/authentication/authentication.module.ts

import { AuthenticationComponent } from './authentication.component'
import { routing } from './authentication.routing'
import { HelpComponent } from './help/help.component'
import { RegisterComponent } from './register/register.component'
import { LoginComponent } from './login/login.component'
import { NgModule } from '@angular/core'
import { CommonModule } from '@angular/common'

@NgModule({
imports: [
CommonModule,
routing, // import routing
],
declarations: [
AuthenticationComponent,
LoginComponent,
RegisterComponent,
HelpComponent,
],
})
export class AuthenticationModule

模块化开发 Angular 应用 [含懒加载]_前端_05

Angular 模块不是 JavaScript 模块

别把 ​​Angular​​​ 模块和 ​​JavaScript​​​ 模块混淆。​​Angular​​​ 模块是类,用 ​​@NgModule​​​ 进行标识。另一方面,当我们使用 ​​Typescript​​​ 关键字 ​​import​​​ 导入模块时,我们在导入一个 ​​JavaScript​​​ 模块。该模块可以包含 ​​Angular​​ 模块。

Angular 模块

// src/app/app.module.ts

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

JavaScript 模块

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

本文是译文,采用的是意译的方式,其中加上个人的理解和注释,原文地址是:malcoded.com/posts/angul…


举报

相关推荐

0 条评论