Angular 使用笔记【依赖注入(有例子)】【constructor & ongOnInit】 【组件传值】【ngSwitch】

  • angular中的服务:多个组件可以共享同一数据,服务可从远程服务器中异步获取数据。
  • 在组件中使用服务的步骤:1. 导入服务; 2. 声明服务; 3. 注入服务
  • @Injectable({provideIn: 'root'})是每个angular服务定义中的基本元素。
  • 你可以在三种位置之一设置元数据,以便在应用的不同层级使用提供商来配置注入器:1. 服务本身的@Injectable()装饰器【provideIn】; 2. NgModule的@NgModule()装饰器 【provides】; 3. 组件的@component装饰器中 【provides】
  • [{ provide: Logger, useClass: Logger }],第一个Logger是令牌,第二个属性是类提供商定义对象
  • 依赖对象的创建方式为: useClass, useValue, useExisting, useFactory
  • Provider:(classProvider, valueProvider, existingProvider, FactoryProvider)
  • Angular中,Provider描述了注入器(Injector)如何初始化令牌(Token)所对应的依赖服务。Provider一个运行时的依赖,注入器依靠它来创建服务对象的实例。
  • 接口,方法,字符串不能被当做一个类来处理,所以引入了new InjectionToken()对象注册依赖的提供商,然后我们在@Inject()的帮助下,我们把这个配置对象注入到需要它的构造函数中,最后我们就可以使用最初的那个对象了.

以下是一个测试,关于useClass, useValue, new InjectionToken

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class CarService {
  color: string = 'test-CarService';
  constructor() {}
}
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class AnimalService {
  emoji: string = 'test--AnimalService';
  constructor() {}
}
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class FlowerService {
  emoji: string = 'test--FlowerService';
  constructor() {}
}
import { InjectionToken } from '@angular/core';

export interface StudentType {
  name: string;
  age: number;
}

export const student: StudentType = {
  name: 'lee si',
  age: 12
};

export const StudentToken = new InjectionToken<StudentType>('student go');
// 非类提供商

以上4个全部注入下面这个组件:

const CarServiceConst = { color: 'in const type' }; // 也可在此处修改

providers: [
    { provide: FlowerService, useValue: { emoji: 'useValue works' } },
    { provide: CarService, useValue: CarServiceConst },
    { provide: AnimalService, useClass: FlowerService }, // useClass里的service无需在构造函数里注入
    // { provide: AnimalService, useClass: CarService } 这样animal.emoji的值会是undefined
    // 如果useClass和provide是同一个service,可以不用写在providers里
    { provide: StudentToken, useValue: student },
    // { provide: StudentFormToken, useClass: StudyFormDefinition } //?StudyFormDefinition
  ]

。。。
 ngOnInit() {
    console.log('>>>>>> test--FlowerService >|', this.flowerService.emoji);
    console.log('>>>>>> test--CarService >|', this.carService.color);
    console.log('>>>>>> test--AnimalService >|', this.animalService.emoji);
    console.log(
      '>>>>>> test new InjectionToken<>() >|',
      this.studentType.name + this.studentType.age
    );
    // console.log('>>>>>> 测试中', this.studyFormDefinition.startup);
  }

打印如下: 


useClass和useExisting的区别:

useExisting会是同一实例,useClass会是新实例。还是上面这个例子,新增加一个trainService:

import { Injectable } from '@angular/core';

@Injectable({ providedIn: 'root' })
export class TrainService {
  color: string = 'test-TrainService';
  constructor() {}
}

在要注入的这个组件写一个按钮,目的是改变carService的值:

click() {
    this.carService.color = 'change together?';
    console.log('>>>>>> test--TrainService >|', this.trainService.color);
    console.log('>>>>>> test--CarService >|', this.carService.color);
  }

下面看2种情况:

情况1,使用useClass:

 { provide: TrainService, useClass: CarService } // 这样carService会是2个实例

打印如下:

 

情况2,使用useExisting:

{ provide: TrainService, useExisting: CarService } // 这样carService会是1个实例

打印如下:



1. constructor用法:

constructor应该是ES6中明确使用constructor来表示构造函数的,构造函数使用在class中,用来做初始化和给属性赋值操作。当包含constructor的类被实例化时,构造函数将被调用。

 constructor也有其用武之地,其主要作用是注入依赖。constructor中注入的依赖,就可以作为类的属性被使用了。

 constructor是在组件就实例化的时候就已经调用了,这也就是说,在constructor中我们是取不到输入属性的值的。,在constructor中不适合进行任何与组件 通信类似的复杂操作,一般在constructor中值进行一些简单的初始化 工作:依赖注入,变量初始化等。

// parent.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'exe-parent',
  template: `
    <h1>Welcome to Angular World</h1>
    <p>Hello {{name}}</p>
    <exe-child [pname]="name"></exe-child>   <!-- 绑定到子组件的属性 -->
  `,
})
export class ParentComponent {
  name: string;

  constructor() {
    this.name = 'God eyes';
  }
}
// child.component.ts

import { Component, Input, OnInit } from '@angular/core';

@Component({
    selector: 'exe-child',
    template: `
     <p>父组件的名称:{{pname}} </p>
    `
})
export class ChildComponent implements OnInit {
    @Input()
    pname: string; // 父组件的输入属性

    constructor() {
        console.log('ChildComponent constructor', this.pname); // this.name=undefined
    }

    ngOnInit() {
        // 只有父组件的模板中pname绑定生效后,才执行ngOnInit,所以属性绑定应该在
        // ngOnInit内执行相应操作
        console.log('ChildComponent ngOnInit', this.pname); // this.name=God eyes
    }
}

 * 使用构造函数初始化(但直接变量赋值方法更简单):

export class AppComponent {
  title: string;
  myHero: string;

  constructor() {
    this.title = 'Tour of Heroes';
    this.myHero = 'Windstorm';
  }
}

 * 直接变量赋值方法:【推荐】

export class AppComponent {
  title = 'Tour of Heroes';
  myHero = 'Windstorm';
}

2. [ngSwitch]

有一组单选按钮,选中是myVal会改变,ngSwitch会去循环每个case,如果找到了就显示那条case中的数据,不然显示default中的数据

<div>
    <h2>ngSwitch</h2>
        <input name="myVal" type="radio" title="" value="1" (click)="changeValue()">1
        <input name="myVal" type="radio" title="" value="2" (click)="changeValue()">2
        <input name="myVal" type="radio" title="" value="3" (click)="changeValue)">3
        <input name="myVal" type="radio" title="" value="4" (click)="changeValue()">4
        <input name="myVal" type="radio" title="" value="5" (click)="changeValue()">5
        <hr>
       <span [ngSwitch]="myVal">
          <span *ngSwitchCase="'1'">ONE</span>
          <span *ngSwitchCase="'2'">TWO</span>
          <span *ngSwitchCase="'3'">THREE</span>
          <span *ngSwitchCase="'4'">FOUR</span>
          <span *ngSwitchCase="'5'">FIVE</span>
          <span *ngSwitchDefault>other</span>
        </span>
</div>

当[ngSwitch]里的myVal=2时,显示TWO

3. 父组件向子组件传值

<!-- 将userName的值通过[name]属性传给子组件 -->

<!-- 父组件html -->
<app-child [name]='userName'></app-child>
//父组件ts

//要传的数据userName
userName = 'user1';
//子组件ts
 import { Component,OnInit,Input, Output, EventEmitter} from '@angular/core';
 @Component({
  selector: 'app-child',
  templateUrl: './app-child.component.html'
})
export class AppChildComponent implements OnInit {
 @Input() name:string;
 
  ngOnInit() {
    console.log(this.name)   //'user1'
  }
}
 

 

export class Hero {
  name: string;
}

export const HEROES = [
  {name: 'Dr IQ'},
  {name: 'Magneta'},
  {name: 'Bombasto'}
];
//父组件
import { Component } from '@angular/core';
import { HEROES } from './hero';

@Component({
  selector: 'app-hero-parent',
  template: `
 <h2>{{master}} controls {{heroes.length}} heroes</h2>
 <app-hero-child *ngFor="let hero of heroes" [hero]=hero [master]="master"></app-hero-child>
  `
})
export class HeroParentComponent {
heroes = HEROES;
master = "Matser"
}
//子组件
import { Component, Input } from '@angular/core';
import { Hero } from './hero';

@Component({
  selector: 'app-hero-child',
  template: `
<h2>{{hero.name}} says:</h2>

<p>I, {{hero.name}},am at your service, {{master}}</p>
  `
})
export class HeroChildComponent {
@Input() hero: Hero;
@Input() master: string;
}

4. 子组件向父组件传值

子组件暴露一个 EventEmitter 属性,当事件发生时,子组件利用该属性 emits(向上弹射)事件。父组件绑定到这个事件属性,并在事件发生时作出回应。


angular 报错: Circular dependency detected:

Angular 不允许模块之间出现循环依赖,所以不要让模块'A'导入模块'B',而模块'B'又导入模块'A'。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值