模板表达式操作符
管道操作符 AsyncPipe
Angular 管道对像这样的小型转换来说是个明智的选择。 管道是一个简单的函数,它接受一个输入值,并返回转换结果。[json](https://angular.cn/api/common/JsonPipe) 管道对调试绑定特别有用:
<div>{{currentHero | json}}</div>
安全导航操作符 ( ?. ) 和空属性路径
- 表达式会在它遇到第一个空值的时候跳出。 显示是空的,但应用正常工作,而没有发生错误。
在像
[a](https://angular.cn/api/router/RouterLinkWithHref)?.b?.c?.d这样的长属性路径中,它工作得很完美<div>The null hero's name is {{nullHero?.name}}</div>
非空断言操作符(!)
如果你打开了严格控制检测,那就要用到这个模板操作符,而其它情况下则是可选的。
- 它只是告诉 TypeScript 的类型检查器对特定的属性表达式,不做 “严格空值检测”。
也就是说,null和undefined在常规模式下,是其它所有类型的子类型,变量可不赋值或任意赋值为null或undefined;如果使用严格空值检测,只要类型声明没有声明为undefined/null(包括联合声明类型),就不能赋值为null/undefined。
因此,在开启严格控制检测的情况下:
如果无法在运行类型检查器期间确定变量是否
null或undefined,则会抛出错误。
这就引出了非空断言操作符:
通过应用后缀非空断言运算符!来告诉类型检查器不要抛出错误。
在tslint.json中配置no-none-null-assertion,不允许非空断言
// Compiled with --strictNullCheckslet x: number;let y: number | undefined;let z: number | null | undefined;x = 1; // Oky = 1; // Okz = 1; // Okx = undefined; // Errory = undefined; // Okz = undefined; // Okx = null; // Errory = null; // Errorz = null; // Okx = y; // Errorx = z; // Errory = x; // Oky = z; // Errorz = x; // Okz = y; // Ok
<div *ngIf="hero">The hero's name is {{hero!.name}}</div
计算属性
does angular have the “computed property” feature like in vue.js? 最高赞
组件交互
1. 常规输入属性@Input
2. setter截听@Input
3. ngOnChanges
当需要监视多个、交互式输入属性的时候,本方法比用属性的 setter 更合适。
4. 子传父@Output
5. 通过服务传递 (可以兄弟组件之间)
—- 以下少用
6. 父组件通过模板变量#xxx控制子组件(只能在html模板中)
7. 父组件的类访问子组件(在ts中)
当父组件类需要这种访问时,可以把子组件作为 ViewChild,注入到父组件里面。
单向数据流
import { AfterViewInit, ViewChild } from '@angular/core';import { Component } from '@angular/core';import { CountdownTimerComponent } from './countdown-timer.component';@Component({selector: 'app-countdown-parent-vc',template: `<h3>Countdown to Liftoff (via ViewChild)</h3><button (click)="start()">Start</button><button (click)="stop()">Stop</button><div class="seconds">{{ seconds() }}</div><app-countdown-timer></app-countdown-timer>`,styleUrls: ['../assets/demo.css']})export class CountdownViewChildParentComponent implements AfterViewInit {@ViewChild(CountdownTimerComponent)private timerComponent: CountdownTimerComponent;seconds() { return 0; }ngAfterViewInit() {// Redefine `seconds()` to get from the `CountdownTimerComponent.seconds` ...// but wait a tick first to avoid one-time devMode// unidirectional-data-flow-violation errorsetTimeout(() => this.seconds = () => this.timerComponent.seconds, 0);}start() { this.timerComponent.start(); }stop() { this.timerComponent.stop(); }}
[ngAfterViewInit()](https://angular.cn/api/forms/NgForm#ngAfterViewInit)生命周期钩子是非常重要的一步。被注入的计时器组件只有在 Angular 显示了父组件视图之后才能访问,所以它先把秒数显示为 0.
然后 Angular 会调用ngAfterViewInit生命周期钩子,但这时候再更新父组件视图的倒计时就已经太晚了。Angular 的单向数据流规则会阻止在同一个周期内更新父组件视图。应用在显示秒数之前会被迫再等一轮。
使用setTimeout()来等下一轮,然后改写seconds()方法,这样它接下来就会从注入的这个计时器组件里获取秒数的值。
ViewChild
访问组件
@ViewChild(NzCarouselComponent, { static: true }) private nzCarousel: NzCarouselComponent;
访问templateRef
@ViewChild('dot', { static: true }) dotRef: TemplateRef<any>;
访问指令
@ViewChild(AdDirective, {static: true}) adHost: AdDirective;
动态组件
指令
AdDirective 注入了 [ViewContainerRef](https://angular.cn/api/core/ViewContainerRef) 来获取对容器视图的访问权,这个容器就是那些动态加入的组件的宿主。
import { Directive, ViewContainerRef } from '@angular/core';@Directive({selector: '[ad-host]',})export class AdDirective {constructor(public viewContainerRef: ViewContainerRef) { }}
加载组件
ng-template
<ng-template ad-host></ng-template>
解析组件
ComponentFactoryResolver
ViewContainerRef
entryComponent
export class AdBannerComponent implements OnInit, OnDestroy {@Input() ads: AdItem[];currentAdIndex = -1;// AdDirective 曾在它的构造函数中注入了一个 ViewContainerRef。// 因此这个指令可以访问到这个你打算用作动态组件宿主的元素。@ViewChild(AdDirective, {static: true}) adHost: AdDirective;interval: any;constructor(private componentFactoryResolver: ComponentFactoryResolver) { }ngOnInit() {this.loadComponent();this.getAds();}ngOnDestroy() {clearInterval(this.interval);}loadComponent() {this.currentAdIndex = (this.currentAdIndex + 1) % this.ads.length;const adItem = this.ads[this.currentAdIndex];const componentFactory = this.componentFactoryResolver.resolveComponentFactory(adItem.component);const viewContainerRef = this.adHost.viewContainerRef;viewContainerRef.clear();const componentRef = viewContainerRef.createComponent(componentFactory);(<AdComponent>componentRef.instance).data = adItem.data;}getAds() {this.interval = setInterval(() => {this.loadComponent();}, 3000);}}
entryComponents: [ HeroJobAdComponent, HeroProfileComponent ]
