Angular2 多级注入器详解及实例


Posted in Javascript onOctober 30, 2016

angular2 的依赖注入包含了太多的内容,其中的一个重点就是注入器,而注入器又非常难理解,今天我们不深入介绍注入器的内容,可以参考官方文档,我们今天来说注入器的层级。

也就是组件获取服务的容器会选择具体哪一个。

先简单介绍一个背景:有3个组件AppComponent 根组件、DetailList组件 ( 日志列表组件)、Detail组件( 日志组件)。

Angular2 多级注入器详解及实例

这三个组件会形成一个组件树,对应的我们也可以认为每个组件都会有一个独立的注入器(有时候不会出现,但是可以这么认为)。

加入一个日志服务LoggerService,如果按照我们普通的入门方式,在根模块providers 中提供LoggerService。那么在整个应用程序中,LoggerService只有一个实例,什么意思呢?就是说无论在哪个组件,获取到的都是首次创建的LoggerService,所有组件共用一个服务实例,这有时候会是一个有用的特性,比如我们使用的全局配置。

全局唯一不是我们这次要验证的重点,因为这个太普通,我们这次要说明的是我们如何在每个组件中都获取单独的LoggerService实例,即每个组件的实例都不同。这个就需要对ng2的依赖注入有所了解才可以。

我们逐步来说明如何实现?

为了便于看到这篇短文的同学有所了解,我加入一些基础代码。

1.app.module.ts 应用程序根模块。注意此处我们没有在Providers中注册loggerService。当然注册了通过后面的方法也可以达到我们的目的。

import { NgModule, Optional, SkipSelf, ReflectiveInjector} from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

/* App Root */
import { AppComponent } from './app.component';
import { routing } from './app.routing';
import { Title } from '@angular/platform-browser';
import {MessagesModule, GrowlModule, ButtonModule}from 'primeng/primeng';
import {AppDetailComponent}from './app-detail.component';
import {AppDetailListComponent}from './app-detailList.component';
import {LoggerService}from './logger.service';
let allTitle:string="郭志奇";

@NgModule({
 imports: [
 BrowserModule,
 MessagesModule,
 GrowlModule, ButtonModule
 ],
 declarations: [AppComponent, AppDetailComponent, AppDetailListComponent],//声明当前模块需要的指定 组件信息
 exports: [],
 providers: [Title],
 bootstrap: [AppComponent]
})
export class AppModule {
 constructor( @Optional() @SkipSelf() parentModule: AppModule) {
 console.log(parentModule);
 if (parentModule) {
  throw new Error(
  'AppModule is already loaded. Import it in the AppModule only');
 }
 }
}

2.app.component.ts  应用程序根组件

import { Component, ViewEncapsulation, Host, ViewContainerRef, ReflectiveInjector } from '@angular/core';
import { Title } from '@angular/platform-browser';
import { Message } from 'primeng/primeng';
import {LoggerService}from './logger.service';
@Component({
 selector: 'my-app',
 moduleId: module.id,
 templateUrl: './app.component.html',
 providers: [
  { provide: LoggerService, useClass: LoggerService }
 ]
})
export class AppComponent {
 subtitle = '(Final)';
 private msgs: Message[];
 constructor(private title: Title, @Host() private logger: LoggerService) {
  this.title.setTitle("AppComponent");
 }

 show(): void {
  this.logger.Debug();
 }
}

请注意,我们在跟组件中providers中注册了LoggerService。

3.app.detailList.ts  日志列表中providers中也注册了LoggerService

import {Component, Host}from '@angular/core';
import {LoggerService}from './logger.service';

@Component({
 selector: 'my-detailList',
 templateUrl: './app-detailList.component.html',
 moduleId: module.id,
 providers: [
  { provide: LoggerService, useClass: LoggerService }
 ]
})

export class AppDetailListComponent {
 constructor( private logger: LoggerService) {

 }
 show(): void {
  this.logger.Debug();
 }

}

 4.app.detail.ts  日志组件providers没有注册LoggerService。

import {Component, Host}from '@angular/core';
import {LoggerService}from './logger.service';
@Component({
 selector: 'detail',
 moduleId: module.id,
 templateUrl: './app-detail.component.html',
 providers: [
  // { provide: LoggerService, useClass: LoggerService }
 ]
})

export class AppDetailComponent {
 constructor( private logger: LoggerService) {

 }
 show(): void {
  this.logger.Debug();
 }

}

 现在我们通过chrome来看一下 LoggerService的层级关系。

Angular2 多级注入器详解及实例Angular2 多级注入器详解及实例

 Angular2 多级注入器详解及实例

通过查看依赖关系图,我们可以看到AppComponent组件使用了单独的LoggerService,DetailList组件也使用单独的LoggerService 实例,而Detail组件使用的是父组件DetailList的LoggerService实例。

目前来看没有达到我们的要求,我们的要求是每个组件都有单独的LoggerService实例,那么我们假设Detail组件的providers是我们忘记输入的,很难测试出原因所在。那么我们加入一个@Host()来限制注入器的查找范围。

对于注入器的向上查找方式,请参考官方文档。

为了便于调试,我们加入@Host().

@Host 装饰器将把往上搜索的行为截止在 宿主组件

detail.ts 提示detail组件加入@Host()装饰器

import {Component, Host}from '@angular/core';
import {LoggerService}from './logger.service';
@Component({
 selector: 'detail',
 moduleId: module.id,
 templateUrl: './app-detail.component.html',
 providers: [
  // { provide: LoggerService, useClass: LoggerService }
 ]
})

export class AppDetailComponent {
 constructor( @Host() private logger: LoggerService) {

 }
 show(): void {
  this.logger.Debug();
 }

}

Angular2 多级注入器详解及实例

会提示找不到LoggerService的实例,@Host()的作用就是限制注入器查找到当前组件就停止,不会继续往上查找。所以会出现找不到Providers的错误。

加上providers 的结果就是我们想要的了。

 Angular2 多级注入器详解及实例

完美的解决了多组件使用单独服务实例的问题。

 总结:

1.如果要使组件单独使用服务,那么首先要在providers 中单独注册该服务。很容易理解

2.为了更好的检测可能出现的问题,在组件服务上加入@Host()装饰器,可以尽量早的抛出错误信息

3.使用ng2的debug工具

4.要明确各组件之间的关系,因为不同的组件关系会导致服务的实例的不同

5.服务尽量是模块级,不是应用级。

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

Javascript 相关文章推荐
网页防止tab键的使用快速解决方法
Nov 07 Javascript
js向上无缝滚动,网站公告效果 具体代码
Nov 18 Javascript
多选列表框动态添加,移动,删除,全选等操作的简单实例
Jan 13 Javascript
详解JavaScript中setSeconds()方法的使用
Jun 11 Javascript
Javascript中内建函数reduce的应用详解
Oct 20 Javascript
jquery.multiselect多选下拉框实现代码
Nov 11 Javascript
深入理解AngularJS中的ng-bind-html指令
Mar 27 Javascript
详解使用React全家桶搭建一个后台管理系统
Nov 04 Javascript
微信小程序首页的分类功能和搜索功能的实现思路及代码详解
Sep 11 Javascript
微信小程序顶部导航栏滑动tab效果
Jan 28 Javascript
服务端预渲染之Nuxt(使用篇)
Apr 08 Javascript
微信小程序实现带参数的分享功能(两种方法)
May 17 Javascript
Javascript 跨域知识详细介绍
Oct 30 #Javascript
jquery.validate[.unobtrusive]和Bootstrap实现tooltip错误提示问题分析
Oct 30 #Javascript
JS触摸屏网页版仿app弹窗型滚动列表选择器/日期选择器
Oct 30 #Javascript
js模式化窗口问题![window.dialogArguments]
Oct 30 #Javascript
Chrome不支持showModalDialog模态对话框和无法返回returnValue问题的解决方法
Oct 30 #Javascript
原生JS版和jquery版实现checkbox的全选/全不选/点选/行内点选(Mr.Think)
Oct 29 #Javascript
JavaScript计算值然后把值嵌入到html中的实现方法
Oct 29 #Javascript
You might like
PHP下通过系统信号量加锁方式获取递增序列ID
2009/09/25 PHP
VB中的RasEnumConnections函数返回632错误解决方法
2014/07/29 PHP
php抽象类使用要点与注意事项分析
2015/02/09 PHP
JavaScript中的eval()函数使用介绍
2014/12/31 Javascript
Javascript核心读书有感之表达式和运算符
2015/02/11 Javascript
JavaScript使用yield模拟多线程的方法
2015/03/19 Javascript
js验证上传图片的方法
2015/05/12 Javascript
js实现兼容性好的微软官网导航下拉菜单效果
2015/09/07 Javascript
JQuery+EasyUI轻松实现步骤条效果
2016/02/22 Javascript
JS实现控制文本框的内容
2016/07/10 Javascript
jQuery ajax方法传递中文时出现中文乱码的解决方法
2016/07/25 Javascript
vue 组件中slot插口的具体用法
2018/04/03 Javascript
nodejs读取本地中文json文件出现乱码解决方法
2018/10/10 NodeJs
inquirer.js一个用户与命令行交互的工具详解
2019/05/18 Javascript
JavaScript运行机制实例分析
2020/04/11 Javascript
怎么理解wx.navigateTo的events参数使用详情
2020/05/18 Javascript
Python遍历目录并批量更换文件名和目录名的方法
2016/09/19 Python
python编程羊车门问题代码示例
2017/10/25 Python
python音频处理用到的操作的示例代码
2017/10/27 Python
Python 12306抢火车票脚本 Python京东抢手机脚本
2018/02/06 Python
Python使用pymysql从MySQL数据库中读出数据的方法
2018/07/25 Python
用Python将Excel数据导入到SQL Server的例子
2019/08/24 Python
使用celery和Django处理异步任务的流程分析
2020/02/19 Python
python opencv进行图像拼接
2020/03/27 Python
详解CSS3阴影 box-shadow的使用和技巧总结
2016/12/03 HTML / CSS
html5 的a标签 Href 拨电话的写法
2013/11/04 HTML / CSS
经验丰富大学生村干部自我鉴定
2014/01/22 职场文书
逃课检讨书怎么写
2015/01/01 职场文书
爱心捐款感谢信
2015/01/20 职场文书
酒店财务总监岗位职责
2015/04/03 职场文书
公司管理制度范本
2015/08/03 职场文书
2016年共产党员个人承诺书
2016/03/24 职场文书
导游词幽默开场白
2019/06/26 职场文书
小学生六年级作文之关于感恩
2019/08/16 职场文书
Django中session进行权限管理的使用
2021/07/09 Python
python中数组和列表的简单实例
2022/03/25 Python