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 相关文章推荐
JQuery的ajax基础上的超强GridView展示
Sep 18 Javascript
用Javascript 获取页面元素的位置的代码
Sep 25 Javascript
js实现select跳转功能代码
Oct 22 Javascript
jQuery遍历DOM元素与节点方法详解
Apr 14 Javascript
WebPack基础知识详解
Jan 16 Javascript
安装Node.js并启动本地服务的操作教程
May 12 Javascript
解决vue router组件状态刷新消失的问题
Aug 01 Javascript
详解React项目中碰到的IE问题
Mar 14 Javascript
Vue之beforeEach非登录不能访问的实现(代码亲测)
Jul 18 Javascript
小程序如何写动态标签的实现方法
Feb 05 Javascript
webpack安装配置与常见使用过程详解(结合vue)
Jun 01 Javascript
vue结合el-upload实现腾讯云视频上传功能
Jul 01 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
ThinkPHP查询中的魔术方法简述
2014/06/25 PHP
php Imagick获取图片RGB颜色值
2014/07/28 PHP
PHP session会话操作技巧小结
2016/09/27 PHP
PHP实现电商订单自动确认收货redis队列
2017/05/17 PHP
JavaScript效率调优经验
2009/06/04 Javascript
原生JavaScript实现合并多个数组示例
2014/09/21 Javascript
Jquery $.getJSON 在IE下的缓存问题解决方法
2014/10/10 Javascript
javascript算法题:求任意一个1-9位不重复的N位数在该组合中的大小排列序号
2015/04/01 Javascript
jquery简单的弹出层浮动层代码
2015/04/27 Javascript
jquery实现动静态条形统计图
2015/08/17 Javascript
谈谈PHP中相对路径的问题与绝对路径的使用
2016/08/16 Javascript
Javascript+CSS3实现进度条效果
2016/10/28 Javascript
Sortable.js拖拽排序使用方法解析
2016/11/04 Javascript
three.js绘制地球、飞机与轨迹的效果示例
2017/02/28 Javascript
JS控件bootstrap datepicker使用方法详解
2017/03/25 Javascript
vuex中使用对象展开运算符的示例
2017/09/25 Javascript
微信小程序异步处理详解
2017/11/10 Javascript
vue引入ueditor及node后台配置详解
2018/01/03 Javascript
angularjs $http调用接口的方式详解
2018/08/13 Javascript
基于element-ui的rules中正则表达式
2018/09/04 Javascript
layer弹出子iframe层父子页面传值的实现方法
2018/11/22 Javascript
VUE2.0 ElementUI2.0表格el-table自适应高度的实现方法
2018/11/28 Javascript
jquery实现图片放大镜效果
2020/12/23 jQuery
Python中set与frozenset方法和区别详解
2016/05/23 Python
Python Paramiko模块的使用实际案例
2018/02/01 Python
Python实现修改文件内容的方法分析
2018/03/25 Python
Python imageio读取视频并进行编解码详解
2019/12/10 Python
Python使用Turtle模块绘制国旗的方法示例
2021/02/28 Python
解决TensorFlow训练模型及保存数量限制的问题
2021/03/03 Python
ManoMano英国:欧洲第一家专注于DIY和园艺市场的电商平台
2020/03/12 全球购物
销售演讲稿范文
2014/01/08 职场文书
奖学金个人总结
2015/03/04 职场文书
亮剑观后感500字
2015/06/05 职场文书
党员学习型组织心得体会
2019/06/21 职场文书
JavaWeb实现显示mysql数据库数据
2022/03/19 Java/Android
python_tkinter事件类型详情
2022/03/20 Python