Angular知识点梳理五

本文梳理了Angular中的NgModule常用元数据,详细解释了服务的作用域与唯一性,特别是惰性加载模块的服务管理。此外,还介绍了Angular路由的基本使用、模块部件、路由参数和路由守卫,包括不同类型的路由守卫及其在导航过程中的执行顺序。
摘要由CSDN通过智能技术生成

目录

NgMoudle常用模块

常用元数据

服务的作用域与唯一性

作用域

唯一性

惰性加载模块使用

Angular路由

基本使用方式

常用模块部件

常用事件一览

ActivatedRoute中常用的路由参数

路由守卫


NgMoudle常用模块

NgModule

导入自

为何使用

BrowserModule

@angular/platform-browser

当你想要在浏览器中运行应用时

CommonModule

@angular/common

当你想要使用 NgIf 和 NgFor 时

FormsModule

@angular/forms

当要构建模板驱动表单时(它包含 NgModel )

ReactiveFormsModule

@angular/forms

当要构建响应式表单时

RouterModule@angular/router

要使用路由功能,并且你要用到 RouterLink,.forRoot() 和 .forChild() 时

HttpClientModule

@angular/common/http

当你要和服务器对话时

常用元数据

属性

说明

declarations

属于该模块可声明对象组件指令管道)的列表。

  1. 当编译模板时,你需要确定一组选择器,它们将用于触发相应的指令。

  2. 该模板在 NgModule 环境中编译 —— 模板的组件是在该 NgModule 内部声明的,它会使用如下规则来确定这组选择器:

    • 列在 declarations 中的所有指令选择器。

    • 从所导入的 NgModule 中导出的那些指令的选择器。

组件、指令和管道只能属于一个模块。 如果尝试把同一个类声明在多个模块中,编译器就会报告一个错误。 小心,不要重复声明从其它模块中直接或间接导入的类。

providers

依赖注入提供商的列表。

Angular 会使用该模块的注入器注册这些提供商。 如果该模块是启动模块,那就会使用根注入器。

当需要注入到任何组件、指令、管道或服务时,这些服务对于本注入器的子注入器都是可用的。

惰性加载模块有自己的注入器,它通常是应用的根注入器的子注入器。

惰性加载的服务是局限于这个惰性加载模块的注入器中的。 如果惰性加载模块也提供了 UserService,那么在这个模块的上下文中创建的任何组件(比如在路由器导航时),都会获得这个服务的本模块内实例,而不是来自应用的根注入器的实例。

其它外部模块中的组件也会使用它们自己的注入器提供的服务实例。

要深入了解关于多级注入器及其作用域,参见服务提供商

imports

要折叠(Folded)进本模块中的其它模块。折叠的意思是从被导入的模块中导出的那些软件资产同样会被声明在这里。

特别是,这里列出的模块,其导出的组件、指令或管道,当在组件模板中被引用时,和本模块自己声明的那些是等价的。

组件模板可以引用其它组件、指令或管道,不管它们是在本模块中声明的,还是从导入的模块中导出的。 比如,只有当该模块导入了 Angular 的 CommonModule(也可能从BrowserModule中间接导入)时,组件才能使用NgIfNgFor` 指令。

你可以从 CommonModule 中导入很多标准指令,不过也有些常用的指令属于其它模块。 比如,你只有导入了 Angular 的 FormsModule 时才能使用 [(ngModel)]

exports

可供导入了自己的模块使用的可声明对象(组件指令管道类)的列表。

导出的可声明对象就是本模块的公共 API。 只有当其它模块导入了本模块,并且本模块导出了 UserComponent时,其它模块中的组件才能使用模块中的 UserComponent

默认情况下这些可声明对象都是私有的。 如果本模块没有导出 UserComponent,那么就只有模块中的组件才能使用 UserComponent

导入某个模块并不会自动重新导出被导入模块的那些导入。 模块 B 不会因为它导入了模块 A,而模块 A 导入了 CommonModule 而能够使用 ngIf。 模块 B 必须自己导入 CommonModule

一个模块可以把另一个模块加入自己的 exports 列表中,这时,另一个模块的所有公共组件、指令和管道都会被导出。

重新导出可以让模块被显式传递。 如果模块 A 重新导出了 CommonModule,而模块 B 导入了模块 A,那么模块 B 就可以使用 ngIf 了 —— 即使它自己没有导入 CommonModule

bootstrap

要自动启动的组件列表。

通常,在这个列表中只有一个组件,也就是应用的根组件

Angular 也可以用多个引导组件进行启动,它们每一个在宿主页面中都有自己的位置。

启动组件会自动添加到 entryComponents 中。

entryComponents

那些可以动态加载进视图的组件列表。

默认情况下,Angular 应用至少有一个入口组件,也就是根组件 AppComponent。 它用作进入该应用的入口点,也就是说你通过引导它来启动本应用。

路由组件也是入口组件,因为你需要动态加载它们。 路由器创建它们,并把它们扔到 DOM 中的 <router-outlet> 附近。

虽然引导组件和路由组件都是入口组件,不过你不用自己把它们加到模块的 entryComponents 列表中,因为它们会被隐式添加进去。

Angular 会自动把模块的 bootstrap 中的组件和路由定义中的组件添加到 entryComponents 列表。

而那些使用不易察觉的ViewComponentRef.createComponent()的方式进行命令式引导的组件仍然需要添加。

动态组件加载在除路由器之外的大多数应用中都不太常见。如果你需要动态加载组件,就必须自己把那些组件添加到 entryComponents 列表中。

服务的作用域与唯一性

在聊服务提供商的作用域之前先明确几个概念,什么是急性加载?所谓急性记载就是在程序启动的时候所有模块都被加载。什么是惰性加载?所谓惰性加载就是在真正应用到具体模块的时候再加载指定的模块,也就是按需加载,那么怎么才能实现按需加载那?其实就是应用了路由的模块而已,也叫惰性加载模块。

对于服务而言,如果我们需要在某个组件中应用某个服务那么我们需要在它的构造函数中把对象注入进来,但是对于被注入的对象是怎么来的其实还是有很多需要说明的地方。对于急性加载而言,没有什么特别的地方,如果把服务注册为全局的话(providedIn:"root"),那么在整个应用中都是可以被访问的,换句话说是全局唯一,全局单例的,因为再获取被注入对象的时候,Angular注册器会检查当前是否存在这个对象,存在就直接提供了,不存在创建一个新的并维护这个对象的状态,以供别的地方再使用。对于惰性加载而言,被注入对象的生成方式是不同的,当惰性加载某个模块的时候Angular会先为该模块创建一个子的注册器,然后把根注册器上的服务添加到子注册器上,在该模块上下文中获取的对象时是在子注册器上去操作的,所以就会存在服务对象的作用域与对象单例唯一的问题。

作用域

@Injectable({providedIn:xxxModule/root'})通过providedIn来指定根注册器,还是指定xxxModule的注册器。

唯一性

对于普通服务来说,指定providedIn root,在appModule中提供就可以了。不过对于某个模块同时提供了服务和可声明对象(组件,指令,管道),这时候我们需要该模块被导入到appModule中(提供服务),同时也希望它被导入到其它模块中(提供指令等),这时候当这个其它模块被加载的时候就会创建一个新的子注册器也就是说会创建一个新的服务对象,本来希望服务对象是单例的,现在很明显是多个了,那么如何解决这样的单例问题那?

import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core';

import { UserService } from './user.service';
import { UserServiceConfig } from './user.service';


@NgModule({
  imports:      [ CommonModule ],
  declarations: [ ],
  exports:      [ ],
  providers:    [ UserService ]
})
export class CoreModule {
  constructor (@Optional() @SkipSelf() parentModule: CoreModule) {
    if (parentModule) {
      throw new Error();
    }
  }

  static forRoot(config): ModuleWithProviders {
    return {
      ngModule: CoreModule,
      providers: [
        {provide: UserServiceConfig, useValue: config }
      ]
    };
  }
}


--------------------------------------------------------------
// 在appModule中import的时候直接调用
CoreModule.forRoot(),

惰性加载模块使用

1. 在appModule中导入appRouterModule

2. 在appRouterModule中配置路由
const routes: Routes = [
  {
    path: 'path1',
    loadChildren: './xxx/xxx.module#xxxModuleClass1'
  },
  {
    path: 'path2',
    loadChildren: './xxx/xxx.module#xxxModuleClass2'
  },
  {
    path: '',
    redirectTo: '',
    pathMatch: 'full'
  }
];

@NgModule({
  imports: [
    RouterModule.forRoot(routes)
  ],
  exports: [RouterModule],
  providers: []
})

3. 在特性子模块中导入子路由Module

4. 在子路由模块中配置组件
const routes: Routes = [
  {
    path: '',
    component: xxxComponent
  }
];

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

 

Angular路由

基本使用方式

// 占位符,接收的位置
<router-outlet></router-outlet>

// 跳转方式1
<a routerLink="/xxx" routerLinkActive="active"/> 

// 跳转方式2
this.router.navigate(['/xxx', { id: id }]);


------------------------------------------------------
// 指定name
<router-outlet name="xxx"></router-outlet>

// 跳转到指定name的outlet
<a [routerLink]="[{ outlets: { xxx: ['pathname'] } }]"/>

// 清空
this.router.navigate([{ outlets: { xxx: null }}]);

常用模块部件

路由器部件

含义

Router(路由器)

为激活的 URL 显示应用组件。管理从一个组件到另一个组件的导航

RouterModule

一个独立的 NgModule,用于提供所需的服务提供商,以及用来在应用视图之间进行导航的指令。

Routes(路由数组)

定义了一个路由数组,每一个都会把一个 URL 路径映射到一个组件。

Route(路由)

定义路由器该如何根据 URL 模式(pattern)来导航到组件。大多数路由都由路径和组件类构成。

RouterOutlet(路由出口)

该指令(<router-outlet>)用来标记出路由器该在哪里显示视图。

RouterLink(路由链接)

这个指令把可点击的 HTML 元素绑定到某个路由。点击带有 routerLink 指令(绑定到字符串链接参数数组)的元素时就会触发一次导航。

RouterLinkActive(活动路由链接)

当 HTML 元素上或元素内的routerLink变为激活或非激活状态时,该指令为这个 HTML 元素添加或移除 CSS 类。

ActivatedRoute(激活的路由)

为每个路由组件提供提供的一个服务,它包含特定于路由的信息,比如路由参数、静态数据、解析数据、全局查询参数和全局碎片(fragment)。

RouterState(路由器状态)

路由器的当前状态包含了一棵由程序中激活的路由构成的树。它包含一些用于遍历路由树的快捷方法。

链接参数数组

这个数组会被路由器解释成一个路由操作指南。你可以把一个RouterLink绑定到该数组,或者把它作为参数传给Router.navigate方法。

路由组件

一个带有RouterOutlet的 Angular 组件,它根据路由器的导航来显示相应的视图。

常用事件一览

路由器事件

说明

NavigationStart

事件会在导航开始时触发。

RouteConfigLoadStart

事件会在 Router 惰性加载 某个路由配置之前触发。

RouteConfigLoadEnd

事件会在惰性加载了某个路由后触发。

RoutesRecognized

事件会在路由器解析完 URL,并识别出了相应的路由时触发

GuardsCheckStart

事件会在路由器开始 Guard 阶段之前触发。

ChildActivationStart

事件会在路由器开始激活路由的子路由时触发。

ActivationStart

事件会在路由器开始激活某个路由时触发。

GuardsCheckEnd

事件会在路由器成功完成了 Guard 阶段时触发。

ResolveStart

事件会在 Router 开始解析(Resolve)阶段时触发。

ResolveEnd

事件会在路由器成功完成了路由的解析(Resolve)阶段时触发。

ChildActivationEnd

事件会在路由器激活了路由的子路由时触发。

ActivationEnd

事件会在路由器激活了某个路由时触发。

NavigationEnd

事件会在导航成功结束之后触发。

NavigationCancel

事件会在导航被取消之后触发。 这可能是因为在导航期间某个路由守卫返回了 false

NavigationError

这个事件会在导航由于意料之外的错误而失败时触发。

Scroll

事件代表一个滚动事件。

ActivatedRoute中常用的路由参数

属性

说明

url

路由路径的 Observable 对象,是一个由路由路径中的各个部分组成的字符串数组。

data

一个 Observable,其中包含提供给路由的 data 对象。也包含由解析守卫(resolve guard)解析而来的值。

paramMap

一个 Observable,其中包含一个由当前路由的必要参数和可选参数组成的map对象。用这个 map 可以获取来自同名参数的单一值或多重值。

queryParamMap

一个 Observable,其中包含一个对所有路由都有效的查询参数组成的map对象。 用这个 map 可以获取来自查询参数的单一值或多重值。

fragment

一个适用于所有路由的 URL 的 fragment(片段)的 Observable

outlet

要把该路由渲染到的 RouterOutlet 的名字。对于无名路由,它的路由名是 primary,而不是空串。

routeConfig

用于该路由的路由配置信息,其中包含原始路径。

parent

当该路由是一个子路由时,表示该路由的父级 ActivatedRoute

firstChild

包含该路由的子路由列表中的第一个 ActivatedRoute

children

包含当前路由下所有已激活的子路由

路由守卫

路由守卫的作用是控制路由的行为,比如检查用户是否有权限访问等。Angular中支持的路由守卫如下。

1. 用CanActivate来处理导航某路由的情况,多用来检查是否登录。

2. 用CanActivateChild来处理导航某子路由的情况。

3. 用CanDeactivate来处理从当前路由离开的情况.

4. 用Resolve在路由激活之前获取路由数据。

5. 用CanLoad来处理异步导航到某特性模块的情况。

在分层路由的每个级别上,你都可以设置多个守卫。 路由器会先按照从最深的子路由由下往上检查的顺序来检查 CanDeactivate() 和 CanActivateChild() 守卫。 然后它会按照从上到下的顺序检查 CanActivate() 守卫。 如果特性模块是异步加载的,在加载它之前还会检查 CanLoad() 守卫。 如果任何一个守卫返回 false,其它尚未完成的守卫会被取消,这样整个导航就被取消了。

最后DEMO地址。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值