Angular官网学习笔记

一、Angular概述

**什么是Angular:**一个基于TypeScript构建的开发平台包括:

  • 一个基于组件的框架,用于构建可伸缩的Web应用
  • 一组完美集成的库,涵盖各种功能,包括路由、表单管理、客户端-服务器通信等
  • 一套开发工具,帮助开发、构建、测试、更新代码

**优势:**让更新更容易,可以用最小的成本升级到最新的Angular版本。

1.1知识要点:

1.1.1 组件

组件是构成应用的砖块。 由三个部分组成:带有@Component()装饰器的TypeScript类、Html模板和样式文件。
@Component()装饰器的TypeScript类
@Component()装饰器会指定一下信息

  • 一个CSS选择器,用于定义如何在模板中使用组件。
  • 一个HTML模板,用于指示Angular如何渲染此组件
  • 一组可选的CSS样式,用于定义模板中HTML的外观
1.1.2 模板

每个组件都有一个HTML模板,用于声明该组件的渲染方式。使用内联或文件路径定义
Angular使用额外的语法扩展了HTML,文本插值(向组件中动态的插入动态值)支持属性绑定事件监听指令为模板添加额外功能

1.1.3 依赖注入

满足声明TypeScript类的依赖项,无需操心如何实例化。
指某个类执行其功能所需的服务或对象。依赖项注入(DI)是一种设计模式,此设计模式中类会从外部源请求依赖项而不是创建。

1.1.4 Angular CLI

常用CLI命令:
ng build:把Angular应用编译到一个输出目录中。
ng serve:构建你的应用并启动开发服务器,当有文件变化就重新构建
ng generate:基于原理图生成或修改某些文件
ng test:在指定的项目上运行单元测试。
ng e2e:构建一个Angular应用并启动开发服务器,然后运行端到端测试。

1.1.5 自带库

常用库:
Angular 路由器:高级的客户侧导航功能与基于Angular组件的路由机制。支持惰性加载、嵌套路由、自定义路径匹配规则等。
Angular 表单:同意的表单填报与验证体系。
Angular HttpClient:支持高级的客户端-服务器通讯。
Angular 动画:用于驱动基于应用状态的动画。
Angular PWA:用于构建渐进式Web应用(PWA)的工具,包括Service Worker和Web应用清单。
Angular 原理图:一些搭建脚手架、重构、升级的自动化工具。用于简化大规模应用的开发。

二、详解Angular功能

2.1 组件

创建组件

    ng g component componentName
2.1.1 组件生命周期

生命周期伴随着变更检测,Angular会检查数据绑定属性何时发生变化,并按需更新视图和组件实例。直至销毁组件实例并移除它渲染的模板
组件与指令的生命周期唯一的区别就是指令没有AfterContentInit和AfterContentChecked,因为指令没有投影,组件或指令发生变更检测时都会调用三个变更检测方法:ngDoCheck、ngAfterContentChecked、ngAfterViewChecked
生命周期顺序:
constructor():初始化类,主要用于注入依赖,在所有生命周期钩子之前执行,用于依赖注入或执行简单的数据初始化操作。
ngOnChanges():触发顺序在ngOnInit之前,当绑定有输入属性或输入属性有发生改变时触发,接收当前和上一个属性值的SimpleChanges对象,。
ngOnInit():顺序在ngOnChages()之后。第一次显示数据绑定和设置指令/组件的输入属性后触发,即使没触发ngOnChages()也会触发。只触发一次。
ngDoCheck():自定义的方法,用于检测和处理值的改变。
ngAfterContentInit():在组件内容初始化之后调用。
ngAfterContentChecked():组件每次检查内容时调用。
ngAfterViewInit():组件相应的视图初始化之后调用。
ngAfterViewCeched():组件每次检查视图时调用
ngOnDestory():指令销毁时调用,此处可以反订阅观察对象和分离事件处理器,防止内存泄漏。

1

响应视图的变更
当Angular再变更检测期间遍历视图树时,需要确保子组件中的某个变更不会尝试更改父组件中的属性,因为单向数据流的工作原理如此,这样的更改无法正常渲染。
如果需要做一个上述操作,必须触发一个新的变更检测周期。
举个栗子:

    // 子视图@Component({selector: 'app-child-view',template: `<label for="hero-name">Hero name: </label><input type="text" id="hero-name" [(ngModel)]="hero">`
})
export class ChildViewComponent {hero = 'Magneta';
}//父组件template使用template: `<div>child view begins</div><app-child-view></app-child-view><div>child view ends</div>`
// 父组件的类文件
export class AfterViewComponent implements  AfterViewChecked, AfterViewInit {private prevHero = '';// Query for a VIEW child of type `ChildViewComponent`//注入子视图@ViewChild(ChildViewComponent) viewChild!: ChildViewComponent;ngAfterViewInit() {// viewChild is set after the view has been initializedthis.logIt('AfterViewInit');this.doSomething();}ngAfterViewChecked() {// viewChild is updated after the view has been checkedif (this.prevHero === this.viewChild.hero) {this.logIt('AfterViewChecked (no change)');} else {this.prevHero = this.viewChild.hero;this.logIt('AfterViewChecked');this.doSomething();}}private doSomething() {const c = this.viewChild.hero.length > 10 ? "That's a long name" : '';if (c !== this.comment) {// Wait a tick because the component's view has already been checkedthis.logger.tick_then(() => this.comment = c);}
}
}

在视图合成完之后,就会触发AfterViewInit()AfterViewCheched()钩子,如果修改了这段代码,这个钩子就会立即修改该组件的数据绑定属性comment,测试会报错。
this.logger.tick_then(() => this.comment = c);会把日志的的更新工作推迟一个浏览器JS周期,也就会触发一个新的变更检测周期。

响应被投影内容的变更
内容投影时从组件外部导入HTML内容,并插入在组件模板中指定位置
投影内容会触发AfterContentInit()AfterContentChecked()
需要在父组件中导入

//子组件  <ng-content></ng-content>标签时外来内容的占位符
template: `<div>projected content begins</div><ng-content></ng-content><div>projected content ends</div>`
//父组件
`<after-content><app-child></app-child>
</after-content>`

AfterContent和AfterView类似:不同在于子组件类型不同:

  • AfterView钩子关心的是ViewChildren,这些子组件的元素标签会出现在该组件的模板里面
  • AfterContent:钩子关心的是ContentChildren,这些子组件被Angular投影进该组件中。
    该组件的doSomething()会立即更新该组件的数据绑定属性comment,无需延迟更新以确保正确渲染。

2.2 视图封装

将组件的样式封装在组建的宿主元素中,避免影响其他应用程序。
分三种模式:
ViewEncapsulation.ShadowDom:组件的样式被包含在这个ShadowDom中,外部样式进不来,内部样式出不去
ViewEncapsulation.Emulated:样式局限在组件视图,全局样式可以进来,内部样式出不去
ViewEncapsulation.None:不使用视图封装,Angular会把CSS添加到全局样式中,全局样式可以进来,内部样式可以出去。
使用

@Component({selector: 'app-no-encapsulation',template: `<h2>None</h2><div class="none-message">No encapsulation</div>`,styles: ['h2, .none-message { color: red; }'],encapsulation: ViewEncapsulation.None,
})
export class NoEncapsulationComponent { }

2.3 组件交互

2.3.1 通过输入型绑定 父传子

在子组件中添加@Input()装饰器

    // 子组件export class HeroChildComponent {@Input() hero!: Hero;//为子组件的属性名masterName指定一个别名master@Input('master') masterName = '';}//父组件<app-hero-child*ngFor="let hero of heroes"[hero]="hero"[master]="master"></app-hero-child>export class HeroParentComponent {heroes = HEROES;master = 'Master';}
2.3.2 通过setter截听输入输入属性值变化

使用一个输入属性的setter,拦截父组件中值的变化

//  子组件
@Input()get name(): string { return this._name; }set name(name: string) {this._name = (name && name.trim()) || '<no name set>';}private _name = '';

父组件与上述一致

2.3.3 通过ngOnChanges()来截听输入属性值变化

当需要监听多个、交互式输入属性时可以使用该方法

  @Input() major = 0;@Input() minor = 0;changeLog: string[] = [];ngOnChanges(changes: SimpleChanges) {const log: string[] = [];for (const propName in changes) {const changedProp = changes[propName];const to = JSON.stringify(changedProp.currentValue);if (changedProp.isFirstChange()) {log.push(`Initial value of${propName}set to${to}`);} else {const from = JSON.stringify(changedProp.previousValue);log.push(`${propName}changed from${from}to${to}`);}}this.changeLog.push(log.join(', '));}

父组件不变

2.3.4 父组件监听子组件事件

子组件暴露一个EventEmitter属性,当事件发生,子组件利用该属性emits(向上弹射)事件,父组件绑定到这个事件属性,并在事件发生时做出相应。
使用@Output()装饰器

    // 子组件@Input()  name = '';@Output() voted = new EventEmitter<boolean>();didVote = false;vote(agreed: boolean) {this.voted.emit(agreed);this.didVote = true;}// 父组件template:`<app-voter*ngFor="let voter of voters"[name]="voter"(voted)="onVoted($event)">  //事件属性</app-voter>`export class VoteTakerComponent {agreed = 0;disagreed = 0;voters = ['Dr IQ', 'Celeritas', 'Bombasto'];onVoted(agreed: boolean) {if (agreed) {this.agreed++;} else {this.disagreed++;}}
2.3.5 父子组件通过本地变量互动

在父组件模板中新建一个本地变量待变子组件,利用这个变量来读取子组件的属性和调用子组件的方法。

// 父组件template: `<h3>Countdown to Liftoff (via local variable)</h3><button type="button" (click)="timer.start()">Start</button><button type="button" (click)="timer.stop()">Stop</button><div class="seconds">{{timer.seconds}}</div>//新建变量 timer<app-countdown-timer #timer></app-countdown-timer>`

只可以在父组件的模板中使用该局部变量

2.3.6 通过@ViewChild()来互动

当父组件的类需要依赖于子组件类,此时不能使用本地变量方法,此时可以将子组件作为ViewChild,注入到父组件中。

// 父组件
@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(); }

将子组件的视图插入到父组件类需要做一点额外的操作
必须导入对装饰器Viewchild以及生命周期钩子AfterViewInit的引用,通过@ViewChild()装饰器,将子组件CountdownTimerComponent注入到私有属性timerComponent里面。

2.3.7 父子组件通过服务通讯

父子组件共享一个服务,利用该服务在组件家族内部实现双向通讯。

// 服务
@Injectable()
export class MissionService {
// 通过RxJs来实现双向通讯// Observable string sourcesprivate missionAnnouncedSource = new Subject<string>();private missionConfirmedSource = new Subject<string>();// Observable string streamsmissionAnnounced$ = this.missionAnnouncedSource.asObservable();missionConfirmed$ = this.missionConfirmedSource.asObservable();// Service message commandsannounceMission(mission: string) {this.missionAnnouncedSource.next(mission);}confirmMission(astronaut: string) {this.missionConfirmedSource.next(astronaut);}
}
// 父组件
//注入服务
constructor(private missionService: MissionService) {//接收子组件的传值missionService.missionConfirmed$.subscribe(astronaut => {this.history.push(`${astronaut}confirmed the mission`);});}announce() {const mission = this.missions[this.nextMission++];//向子组件传值this.missionService.announceMission(mission);this.history.push(`Mission "${mission}" announced`);if (this.nextMission >= this.missions.length) { this.nextMission = 0; }}

子组件通过构造函数注入该服务,因为是子组件所以获取到的也是父组件的这个服务实例。
subscript变量在子组件ngOnDestory()钩子函数内被销毁(调用unsubscribe()),防止内存泄漏的保护措施,在父组件中不需要因为服务与父组件的生命周期相同。

2.4 组件样式

特殊的选择器::host、:host-context
:host
每个组件都会关联一个与组件选择器相匹配的元素,该元素被称为宿主元素,模板会渲染到其中。:host伪类选择器可用于创建针对宿主元素自身的样式,而不是针对宿主内部的哪些元素。
host-context
在当前组件宿主元素的祖先节点上查找CSS类,直到文档的根节点为止。只能与其他选择器组合使用。

2.5 父子指令及组件间共享数据

父组件和一个或多个子组件共享数据,使用@Input()@Output()
@Input():允许父组件更新子组件中的数据
@Output():允许子组件向父组件发送数据。

2.6 内容投影

2.6.1 单插槽内容投影

创建一个组件,在其中投影一个组件。
在组件模板中添加,<ng-content>,元素希望投影的内容出现在其中。
栗子:

// 子组件template: `<h2>Single-slot content projection</h2><ng-content></ng-content>`
// 父组件
<app-zippy-basic><p>Is content projection cool?</p>
</app-zippy-basic>

元素是一个占位符,它不会创建真正的DOM元素。的自定义属性被忽略。

2.6.2 多插槽内容投影

一个组件可以具有多个插槽,每一个插槽可以指定一个CSS选择器,选择器可以指定哪些内容放入该插槽。
必须指定投影出现的位置,通过使用和select属性来完成此任务。
栗子

// 子组件template: `<h2>Multi-slot content projection</h2>Default:<ng-content></ng-content>Question:<ng-content select="[question]"></ng-content>`// 父组件<app-zippy-multislot><p question>Is content projection cool?</p><p>Let's learn about content projection!</p>
</app-zippy-multislot>

question属性的将内容投影到带有select=[question] 属性的 <ng-content>元素。
如果组件包含不带select属性的<ng-content>元素,则该实例将接受所有与其他<ng-content>元素都不匹配的投影组件。

2.6.3 有条件的内容投影

后补

2.7 动态组件

当组件数量不多时可以使用ngif来判断component
栗子:

<ng-container *ngIf="radioValue === 'A'"><app-component-a></app-component-a>
</ng-container>
<ng-container *ngIf="radioValue === 'B'"><app-component-b></app-component-b>
</ng-container>
<ng-container *ngIf="radioValue === 'C'"><app-component-c></app-component-c>
</ng-container>

当选项很多时,或者选项通过后端决定等复杂情况下,再用ngif实现会很复杂,代码不容易维护此时需要动态组件,动态的方式来生成或删除component
可以通过ViewContainerRef可以将一个或多个视图附着到组件中的容器,也只有它才可以加载组件。不过可以将新的组件作为其兄弟(节点)的DOM元素(容器),是兄弟不是父子。
步骤:

  1. 创建一个指令 ng g d directiveName
@Directive({selector: '[appDynamic]'
})
export class DynamicDirective {constructor(public viewContainerRef: ViewContainerRef) { }
}
  1. 创建容器
    通过单选框来选择动态加载组件
    锚点设置在ng-template上,
    appDynamic(使用指令)
template:
`<nz-radio-group [(ngModel)]="radioValue" (ngModelChange)="radioValueChange()"><label nz-radio nzValue="A">A</label><label nz-radio nzValue="B">B</label><label nz-radio nzValue="C">C</label>
</nz-radio-group>
<ng-template appDynamic></ng-template>`
class类:/*所有的组件列表*/componentList = {componentA: ComponentAComponent,componentB: ComponentBComponent,componentC: ComponentCComponent,}/*利用viewChild获取模板元素*/@ViewChild(DynamicDirective) componentHost!:DynamicDirective;radioValue: string = 'A';radioValueChange() {/** 获取到模板元素,因为用viewChild获取dom时定义的undefined 所以需要手动as定义一下类型*/const viewContainerRef = this.componentHost.viewContainerRef;/*将模板上的元素清空*/viewContainerRef.clear();/*创建组件*/viewContainerRef.createComponent(this.getComponent(this.radioValue));}getComponent(radioValue: string): any {if (radioValue === 'A') {return this.componentList['componentA']} else if (radioValue === 'B') {return this.componentList['componentB']} else {return this.componentList['componentC']}}

2.8 Angular元素(Element)

Angular元素就是打包成自定义元素的Angular组件

3 模板

Angular使用额外的特性扩展了模板中的HTML语法,Angular模板只是UI的一个片段,因此不包含<html><body><base>等元素。并且不支持模板中使用<script>元素

3.1 文本插值

**插值:**将表达式嵌入到被标记的文本中。默认情况下使用双花括号{{}}作为定界符。

3.2 模板语句

模板语句是可在HTML中用于响应用户事件的方法或属性。

<button type="button" (click)="deleteHero()">Delete hero</button>

**语法:**与模板表达式一样,模板语句使用类似与JS的语言,支持赋值和带分号的串联表达式,不允许使用

  • new
  • ++、–
  • 按位运算符,| &
  • 管道操作符

3.3 绑定

3.3.1 属性绑定

类似与Property绑定,但是不能直接在方括号之间放置元素的Property,而是在Attribute名前加上前缀attr,后跟.,然后,使用解析为字符串的表达式设置Attribute值。

<p [attr.attribute-you-are-targeting]="expression"></p>

当表达式解析为nullundefined时,Angular会完全删除该Attribute。
ARIA Attribute

<button type="button" [attr.aria-label]="actionName">{{actionName}} with Aria</button>

绑定colSpan
colspan帮助以编程方式让表格保持动态
将[attr.colspan]设置为等于某个表达式。

<tr><td [attr.colspan]="1 + 1">One-Two</td></tr>
3.3.2 类和样式绑定

使用类和样式绑定从元素的class属性中添加和删除css类名,以及动态设置样式。
绑定到单个CSS class
[class.sale]='onSale'
sale为类名
当表达时onSale为真值时,Angular会添加类,为假时会删除类,undefined除外
绑定到多个CSS class类
[class]='classExpression'
calssExpression可以为:

  • 用空格分隔的类名字符串 "my-class-1 my-class-2 my-class-3"
  • 以类名作为键名并将真或假表达式作为值的对象。 {foo: true, bar: false}
  • 类名的数组 ['foo', 'bar']
    绑定到单一样式
    创建单个样式绑定以style前缀后跟点加CSS样式的名称。
// 中线格式
<nav [style.background-color]="expression"></nav>
// 驼峰格式
<nav [style.backgroundColor]="expression"></nav>

绑定到多个样式

<nav [style]='navStyle'>
navStyle = 'font-size: 1.2rem; color: cornflowerblue;';
3.3.3 事件绑定

<button (click)="onSave()">Save</button>
click:事件名
onSave():模板语句

3.3.4 属性绑定

属性绑定在单一方向上将值从组件的属性送到目标元素的属性。
绑定到属性:要绑定到元素的属性,放到方括号内,将此属性标识为目标属性。
<img alt="item" [src]="itemImageUrl">
colspan 和 colSpan
最容易混淆的地方是 colspan 这个 Attribute 和 colSpan 这个 Property。请注意,这两个名称只有一个字母的大小写不同。
<tr><td [colSpan]="1 + 1">Three-Four</td></tr>

3.3.5 双向绑定

双向绑定将属性和事件绑定结合在一起
Angular 的双向绑定语法是方括号和圆括号的组合 [()]。[] 进行属性绑定,() 进行事件绑定
<app-sizer [(size)]="fontSizePx"></app-sizer>
**原理:**属性绑定展示数据,事件绑定修改数据

3.4 管道

管道用于转换数据进行显示。
内置管道:

uppercase: 转换成大写字符 {{ str | uppercase }}

lowercase: 转换成小写 {{ str | lowercase }}

date: 日期格式转换 {{ today | date: ‘yyyy-MM-dd HH:mm:ss’ }}

number: 数字转换 {{ p | number:‘1.2-4’ }} 【格式:{最少整数位数}.{最少小数位数}-{最多小数位数},即保留2~4位小数】

slice: 字符串截取 {{ ‘hello world!’ | slice:0:3 }} //输出结果:“hel”
管道的优先级比三目运算符高
**使用参数和管道链来格式化数据:**模板表达式 {{ amount | currency:'EUR' }} 会把 amount 转换成欧元。紧跟在管道名称(currency)后面的是冒号(:)和参数值(‘EUR’)。多个参数使用:分割开来
{{ amount | currency:'EUR':'Euros '}}
管道串联:{{ birthday | date | uppercase}}
自定义管道
创建指令: ng g p pipeName

3.5 模板变量

模板变量事项在模板的另一部分使用这个部分的数据。
可以引用的东西:

  • 模板中的DOM元素
  • 指令或组件
  • 来自ng-template的TemplateRef
  • Web组件
    **语法:**使用井号#来声明一个模板变量,可以在组件模板中的任何地方引用某个模板变量。
<input #phone placeholder="phone number" /><!-- lots of other elements --><!-- phone refers to the input element; pass its `value` to an event handler -->
<button type="button" (click)="callPhone(phone.value)">Call</button>

模板变量的赋值:

  • 如果在组件上声明变量,该变量就会引用该组件实例。
  • 如果在标准的HTML标记上声明变量,该变量就会引用该元素。
  • 如果在<ng-template>元素上声明变量,该变量就会引用一个TemplateRef实例来代表此模板。
    ***TemplateRef:***表示一个内嵌模板,可用于实例化内嵌的视图。要想根据模板实例化内嵌的视图,可以使用ViewContainerRefcreateEmbeddedView()方法。
    **作用域:**模板变量的范围为声明它们的模板。
    同样,诸如 *ngIf*ngFor 类的结构指令或 <ng-template> 声明会创建一个新的嵌套模板范围,就像 JavaScript 的控制流语句(例如 if 和 for 创建新的词法范围。你不能从边界外访问这些结构指令之一中的模板变量。
    **在嵌套模板中访问:**内部模板可以访问外模板定义的模板变量。
<input #ref1 type="text" [(ngModel)]="firstExample" />
<span *ngIf="true">Value: {{ ref1.value }}</span>

<span> 上的 *ngIf 会创建一个新的模板范围,其中包括其父范围中的 ref1 变量。
外部的父模板访问子范围中的变量不行。
模板输入变量
是一个具有在创建该模板实例时设置的值的变量

<ul><ng-template ngFor let-hero let-i="index" [ngForOf]="heroes"><li>Hero number {{i}}: {{hero.name}}</ng-template>
</ul>

实例化<ng-template>时,可以传递国歌命名值,这些值可以绑定到不同的模板输入变量。输入变量的let-声明的右侧可以指定应该用于该变量的值。

4. 指令

指令:为元素添加额外的行为的类。使用指令可以管理表单、列表、样式以及可以让用户看到的内容
不同类型的指令:

  • 组件:带有模板的指令。
  • 属性型指令:更改元素、组件或其他指令的外观或行为的指令。
  • 结构型指令:通过添加和删除DOM元素来改变DOM布局。

4.1 内置指令

属性型指令会监听并修改其他HTML元素和组件的行为、Attribute(属性)和Property(特性)

4.1.1 内置属性指令

通用指令:

  • NgClass:添加和删除一组CSS类
  • NgStyle:添加和删除一组HTML样式。
  • NgModel:将双向数据绑定添加到HTML表单元素
    内置指令只会使用公开API。不会访问任何无法被其他指令访问的私有API。
NgClass

NgClass:同时添加或删除多个CSS类。
<div [ngClass]="isSpecial ? 'special' : ''">This div is special</div>
如果时添加或删除单个类,可以使用类绑定
类绑定:[class.sale]="onSale"
与方法一起使用:
通过一个对象来设置属性currentClasses,该对象每个键(key)都是一个CSS类名。如果键为true,则ngClass添加该类。如果为false则删除该类。

currentClasses: Record<string, boolean> = {};
/* . . . */
setCurrentClasses() {// CSS classes: added/removed per current state of component propertiesthis.currentClasses =  {saveable: this.canSave,modified: !this.isUnchanged,special:  this.isSpecial};
}

使用:
<div [ngClass]="currentClasses">This div is initially saveable, unchanged, and special.</div>

NgSyle

NgStyle向组件添加的都是内联样式。
栗子:

currentStyles: Record<string, string> = {};
/* . . . */
setCurrentStyles() {// CSS styles: set per current state of component propertiesthis.currentStyles = {'font-style':  this.canSave      ? 'italic' : 'normal','font-weight': !this.isUnchanged ? 'bold'   : 'normal','font-size':   this.isSpecial    ? '24px'   : '12px'};
}
//使用
<div [ngStyle]="currentStyles">This div is initially italic, normal weight, and extra large (24px).
</div>
4.1.3 内置结构型指令

结构型指令的职责是HTML布局,塑造或重塑DOM的结构,通过添加、移除和操作它们附加的宿主元素来实现。

NgIf

用于宿主元素添加或删除元素
为false则从DOM中移除一个元素及其后代。然后Angular销毁其组件,释放内存和资源。
isActive 为true添加组件到DOM中
<app-item-detail *ngIf="isActive" [item]="item"></app-item-detail>

NgFor条目列表

Ngif与NgFor不可同时在同一个元素上。
用*ngFor的tackBy跟踪条目:
通过跟踪对条目列表的更改,可以减少应用程序对服务器的调用次数。使用*ngFor的trackBy属性,Angular只能更改和重新渲染已更改的条目,而不必重新加载整个条目列表。

// 该方法会返回NgFor应该跟踪的值
trackByItems(index: number, item: Item): number { return item.id; }<div *ngFor="let item of items; trackBy: trackByItems">({{item.id}}) {{item.name}}
</div>
4.1.4 为没有DOM元素的指令安排宿主

<ng-container>是一个分组元素,不会干扰样式或布局,因为Angular不会将其放置在DOM中。当没有单个元素承载指令时可以使用<ng-container>

<ng-container *ngIf="hero">and saw {{hero.name}}. I waved</ng-container><select [(ngModel)]="hero"><ng-container *ngFor="let h of heroes"><ng-container *ngIf="showSad || h.emotion !== 'sad'"><option [ngValue]="h">{{h.name}} ({{h.emotion}})</option></ng-container></ng-container>
</select>
4.1.5 NgSwitch

NgSwitch会根据切换条件显示几个可能的元素中的一个。
NgSwitch是一组指令

  • NgSwitch:一个属性型指令,会改变其伴生指令的行为
  • NgSwitchCase:当其绑定值等于开关值时将其元素添加到DOM中,而在其不等于开关值时将其绑定之移除。
  • NgSwitchDefault:当没有选中的NgSwitchCase时,将其宿主元素添加到DOM中。
<div [ngSwitch]="currentItem.feature"><app-stout-item    *ngSwitchCase="'stout'"    [item]="currentItem"></app-stout-item><app-device-item   *ngSwitchCase="'slim'"     [item]="currentItem"></app-device-item><app-lost-item     *ngSwitchCase="'vintage'"  [item]="currentItem"></app-lost-item><app-best-item     *ngSwitchCase="'bright'"   [item]="currentItem"></app-best-item>
<!-- . . . --><app-unknown-item  *ngSwitchDefault           [item]="currentItem"></app-unknown-item>
</div>

4.2 属性型指令

属性型指令,可以改变DOM元素和Angular组件的外观或行为。
创建指令:ng generate directive highlight
@Directive() 装饰器的配置属性会指定指令的 CSS 属性选择器 [appHighlight]。
@angular/core导入ElementRef。ElementRef的nativeElement属性会提供对宿主DOM元素的直接访问权限。
在指令的 constructor() 中添加 ElementRef 以注入对宿主 DOM 元素的引用,该元素就是 appHighlight 的作用目标。
向 HighlightDirective 类中添加逻辑,将背景设置为黄色。

import { Directive, ElementRef } from '@angular/core';@Directive({selector: '[appHighlight]'
})
export class HighlightDirective {constructor(private el: ElementRef) {this.el.nativeElement.style.backgroundColor = 'yellow';}
}
// 应用指令
<p appHighlight>Highlight me!</p>
4.2.1 处理用户事件

要添加事件处理程序,每个事件处理程序都需要带有@HostListener()装饰器。

Angular官网学习笔记相关推荐

  1. Vue 官网学习笔记

    VUE介绍 vue git 地址:https://github.com/vuejs/vue/projects Vue 官网教程地址:https://cn.vuejs.org/v2/guide/inst ...

  2. STL官网学习笔记——set_intersection

    练习题有做到 set_intersection 的相关练习,看别人写的看不懂,就找到了STL的官方文档,翻译加总结如下,如果单纯想要实例,可以去后面直接复制粘贴代码. STL的地址:http://st ...

  3. Angular官网学习4:Angular入门,你的第一个应用(4)输出

    在本节中,将设置商品提醒组件,当用户点击'Notify Me'的时候,像商品列表组件发出事件. 1.打开 product-alerts.component.ts, 从 @angular/core 中导 ...

  4. vue官网学习笔记(九)组件基础

    基本示例 这里有一个Vue组件的示例: // 定义一个名为 button-counter 的新组件 Vue.component('button-counter', {data: function () ...

  5. JavaWeb黑马旅游网-学习笔记03【登陆和退出功能】

    Java后端 学习路线 笔记汇总表[黑马程序员] JavaWeb黑马旅游网-学习笔记01[准备工作] JavaWeb黑马旅游网-学习笔记02[注册功能] JavaWeb黑马旅游网-学习笔记03[登陆和 ...

  6. PCL官网学习OpenNI Grabber 调用奥比中光Astra s 遇到问题openni2_grabber.cpp @ 325 : No devices connected.

    PCL官网学习OpenNI Grabber 调用奥比中光Astra s 遇到问题openni2_grabber.cpp @ 325 : No devices connected. 问题描述 termi ...

  7. JavaWeb黑马旅游网-学习笔记10【项目代码】

    Java后端 学习路线 笔记汇总表[黑马程序员] JavaWeb黑马旅游网-学习笔记01[准备工作] JavaWeb黑马旅游网-学习笔记02[注册功能] JavaWeb黑马旅游网-学习笔记03[登陆和 ...

  8. rt-thread官网应用笔记(设备驱动类)配套资料

    在rt-thread官网学习设备驱动类应用笔记时发现文章中给出的示例代码链接已经失效,在论坛中找到了该资源,现整理记录在此. 官网设备驱动类应用笔记网址:https://www.rt-thread.o ...

  9. JavaWeb黑马旅游网-学习笔记09【旅游线路收藏】

    Java后端 学习路线 笔记汇总表[黑马程序员] JavaWeb黑马旅游网-学习笔记01[准备工作] JavaWeb黑马旅游网-学习笔记02[注册功能] JavaWeb黑马旅游网-学习笔记03[登陆和 ...

最新文章

  1. 剑指offer之队列的最大值
  2. Web安全之点击劫持(ClickJacking)
  3. cassandra可视化工具_耗时1个月整理!160种Python标准库、第三方库和外部工具都有了...
  4. html 文件域变滑块,小巧的jQuery区域范围滑块插件noUiSlider
  5. 电子科技大学计算机学院王刚,电子科技大学-团体程序设计天梯赛.PDF
  6. java二叉树是什么_java数据结构二叉树是什么?特点是?
  7. 《像外行一样思考,像专家一样实践》
  8. 程序跳转到访问一个确定的地址0x100000
  9. IE无法打开新链接的问题
  10. 整理12种电脑有趣屏保
  11. 将ip电话注册到服务器上,华为IP电话配置步骤.doc
  12. 【SD自动记账】SD与FI的集成部分
  13. 随机森林原始论文_【科普天地】2020年还需要阅读的10篇人工智能论文(附链接)...
  14. 房价预测(基于决策树算法)
  15. Redis实现抢红包
  16. html中如果设置颜色为半透明状态,css如何利用transparent属性设置透明度?
  17. 玩转华为ENSP模拟器系列 | 配置多段拼接场景下的伪线BFD示例
  18. 制作Centos7自动安装镜像(五)
  19. 画世界上传图片提交到服务器_webuploader实现上传图片到服务器功能
  20. 使用FRP远程访问TP-LINK路由器管理页面

热门文章

  1. Java中的poi是什么_java poi介绍
  2. Mac重复文件清理软件Cisdem Duplicate Finder Mac
  3. 网传迅雷遭遇“脱裤门” 官方回应:恶意造谣
  4. matlab状态方程 传递函数 可控性,实验一 MATLAB系统的传递函数和状态空间表达式的转换...
  5. 系统优化总结—系统层面
  6. 让Google音乐替你选歌~
  7. linux防火墙的设置
  8. openresty Aes解密 Java 加密
  9. Java风车动画代码_纯DOM+CSS3实现简单的小风车动画
  10. IB物理的费曼图怎么考?