zoukankan      html  css  js  c++  java
  • Angular:ViewProviders和Providers的区别

    在Angular中使用依赖注入(DI)的时候,我们一般会使用providers。其实要做同样的事我们还有另外一个选择:viewProviders
    viewProviders允许我们定义只对组件的view可见的provider。下面我们用例子详细的说明这一点。
    假设我们有一个简单的服务:

    // myService.service.ts
    import { Injectable } from '@angular/core';
    
    @Injectable()
    export class MyService{
      testIfGetService(where){
        console.log('Got My Service in ' + where);
      }
    }
    

    这个服务很简单,只需要打印出在哪里调用了该服务。
    然后有一个子组件,是用来投射到父组件里面的(等会将会看到):

    // child.component.ts
    import { Component } from '@angular/core';
    import { MyService } from './myService.service';
    
    @Component({
      selector: 'vp-child',
      template: `
        <div>This is child!!!</div>
      `
    })
    export class VPChild{
      constructor(
        private service: MyService
      ){
        this.service.testIfGetService('child');
      }
    }
    

    这个组件注入了MyService服务,调用MyServicetestIfGetService方法,并传入child表明这是在child组件调用的。
    还有另外一个子组件,这个组件是用来放在父组件的模板(template)里面的:

    // viewChild.component.ts
    import { Component } from '@angular/core';
    import { MyService } from './myService.service';
    
    @Component({
      selector: 'vp-viewchild',
      template: `
        <div>This is viewChild!!!</div>
      `
    })
    export class ViewVPChild{
      constructor(
        private service: MyService
      ){
        this.service.testIfGetService('viewChild');
      }
    }
    

    这里同样注入MyService服务,调用MyService服务的testIfGetService方法,并传入viewChild
    最后是父组件:

    // parent.component.ts
    import { Component } from '@angular/core';
    import { MyService } from './myService.service';
    @Component({
      selector: 'vp-parent',
      template: `
        <div>This is parent!!!</div>
        <ng-content></ng-content>
        <vp-viewchild></vp-viewchild>
      `,
      providers: [MyService]
    })
    export class VPParent{
      constructor(
        private service: MyService
      ){
        this.service.testIfGetService('parent');
      }
    }
    

    在父组件,用providers注册MyService,然后调用MyServicetestIfGetService传入parent
    然后就像这样使用父组件:

    <vp-parent>
      <vp-child></vp-child>
    </vp-parent>
    

    运行程序,控制台打印出了结果:

    一切就像预期那样!!
    然后,我们用viewProviders代替providers注册MyService,看看会发生什么:

    // parent.component.ts
    import { Component } from '@angular/core';
    import { MyService } from './myService.service';
    @Component({
      selector: 'vp-parent',
      template: `
        <div>This is parent!!!</div>
        <ng-content></ng-content>
        <vp-viewchild></vp-viewchild>
      `,
      viewProviders: [MyService] // <---
    })
    export class VPParent{
      constructor(
        private service: MyService
      ){
        this.service.testIfGetService('parent');
      }
    }
    

    这样修改之后,运行程序,发现报错了:

    如果把contentChild注释掉,就像这样:

    <vp-parent>
      <!-- <vp-child></vp-child> -->
    </vp-parent>
    

    是不会报错的:

    这就说明,在父组件用viewProviders注册的provider,对contentChildren是不可见的。而使用providers注册的provider,对viewChildren和contentChildren都可见!
    补充说明:组件会逐级向上寻找provider,直到找到为止,否则就会抛出错误。就像这里:

    <vp-parent>
      <vp-child></vp-child>
    </vp-parent>
    

    vp-child往上找MyService的provider,结果在vp-parent找到了。但是在用viewProviders的时候,vp-child往上找,也就是到vp-parent,结果没找到,然后又去找vp-parent的父级,还是没找到(因为在这个例子里,我们只在vp-parent注册了MyService),然后又继续往上找……如此找到边界也没找到,所以抛出了一个错误。如果你不希望这样,可以使用@Host做出限制,就像这样:

    constructor(
        @Host() private service: MyService
    ){}
    

    关于@Host()本文不作展开,有兴趣可以自行google。

  • 相关阅读:
    Code Review
    关于calendar修改前的代码和修改后的代码
    程序员必备的代码审查(Code Review)清单
    一个数组中最大子数组的和并且加上测试用例
    阅读build to win的个人感想
    结对编码(柳祎、张许君)
    Review(patener)
    Review [myself]
    Impressions
    Array
  • 原文地址:https://www.cnblogs.com/cme-kai/p/8574284.html
Copyright © 2011-2022 走看看