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 相关文章推荐
JS实现点击图片在当前页面放大并可关闭的漂亮效果
Oct 18 Javascript
JQuery中dataGrid设置行的高度示例代码
Jan 03 Javascript
2014 HTML5/CSS3热门动画特效TOP10
Dec 07 Javascript
js简单实现竖向tab选项卡的方法
May 04 Javascript
javascript实现网页字符定位的方法
Jul 14 Javascript
jQuery实现的鼠标滑过弹出放大图片特效
Jan 08 Javascript
JavaScript 正则表达式中global模式的特性
Feb 25 Javascript
javaScript事件学习小结(四)event的公共成员(属性和方法)
Jun 09 Javascript
jQuery EasyUI右键菜单实现关闭标签/选项卡
Oct 10 Javascript
JavaScript输入框字数实时统计更新
Jun 17 Javascript
vue中将html字符串转换成html后遇到的问题小结
Dec 10 Javascript
JavaScript进阶(二)词法作用域与作用域链实例分析
May 09 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
PHP4引用文件语句的对比
2006/10/09 PHP
ThinkPHP实现二级循环读取的方法
2014/11/03 PHP
php源码分析之DZX1.5加密解密函数authcode用法
2015/06/17 PHP
php实现购物车功能(下)
2016/01/05 PHP
PHP实现原比例生成缩略图的方法
2016/02/03 PHP
PHP实现限制IP访问及提交次数的方法详解
2017/07/17 PHP
node.js 一个简单的页面输出实现代码
2012/03/07 Javascript
对table和ul实现js分页示例分享
2014/02/24 Javascript
Node.js中使用Buffer编码、解码二进制数据详解
2014/08/16 Javascript
Javascript中的Prototype到底是什么
2016/02/16 Javascript
js剪切板应用clipboardData实例解析
2016/05/29 Javascript
基于JavaScript实现轮播图代码
2016/07/14 Javascript
JS制作图形验证码实现代码
2020/10/19 Javascript
Angular2中Bootstrap界面库ng-bootstrap详解
2016/10/18 Javascript
AngularJS指令中的绑定策略实例分析
2016/12/14 Javascript
bootstrap——bootstrapTable实现隐藏列的示例
2017/01/14 Javascript
JS日程管理插件FullCalendar中文说明文档
2017/02/06 Javascript
详解vue.js移动端导航navigationbar的封装
2017/07/05 Javascript
ES6 Array常用扩展的应用实例分析
2019/06/26 Javascript
vue data引入本地图片的两种方式小结
2019/11/13 Javascript
详解vue3中组件的非兼容变更
2021/03/03 Vue.js
详解Python3迁移接口变化采坑记
2019/10/11 Python
python_array[0][0]与array[0,0]的区别详解
2020/02/18 Python
全球知名旅游社区法国站点:TripAdvisor法国
2016/08/03 全球购物
屈臣氏官方旗舰店:亚洲享负盛名的保健及美妆零售商
2019/03/15 全球购物
自荐信包含哪些内容
2013/10/30 职场文书
生产厂厂长岗位职责
2013/12/25 职场文书
《梅花魂》教学反思
2014/04/30 职场文书
启动仪式策划方案
2014/06/14 职场文书
学雷锋志愿者活动方案
2014/08/21 职场文书
滞留工资返还协议书
2014/10/19 职场文书
财务工作失职检讨书
2014/11/21 职场文书
新郎婚礼答谢词
2015/01/04 职场文书
2015年护士工作总结范文
2015/03/31 职场文书
师德师风培训感言
2015/08/03 职场文书
个人落户申请书怎么写?
2019/06/28 职场文书