Angular 指令的不同类型如下:
- 组件 —— 带有模板的指令。这种指令类型是最常见的指令类型。
- 属性型指令 —— 更改元素、组件或其他指令的外观或行为的指令。
- 结构型指令 —— 通过添加和删除 DOM 元素来更改 DOM 布局的指令。由于结构型指令会在 DOM 中添加和删除节点,因此每个元素只能应用一个结构型指令。
内置指令
内置属性型指令:
常见的内置属性型指令 | 作用 |
---|---|
NgClass | 添加和删除一组 CSS 类 |
NgStyle | 添加和删除一组 HTML 样式 |
NgModel | 将数据双向绑定添加到 HTML 表单元素 |
ngClass添加和删除类
- 可用表达式
- 可用对象,key值为class名,value值为布尔类型
//使用表达式
<div [ngClass]="'svg-notification-' + type">11</div>
<div [ngClass]="isSpecial ? 'special' : ''">This div is special</div>
//使用对象
<div [ngClass]="{'status-flag-process': data.controlStatus === 1, 'status-flag-success': data.controlStatus === 2}">22</div>
<div [ngClass]="currentClasses">This div is initially saveable, unchanged, and special.</div>
this.currentClasses = {
saveable: true,
modified: false,
special: true
};
ngStyle设置内联样式
使用对象,key值为style名,value是三元表达式返回对应的样式值
//使用对象
<div [ngStyle]="{'padding-right': data?.flag === 2 ? '8px' : '0','width': type === 'blank' ? '100%' : 'calc(100% - 50px)'}">11</div>
<div [ngStyle]="currentStyles">22</div>
public this.currentStyles = {
'font-style': this.canSave ? 'italic' : 'normal',
'font-weight': !this.isUnchanged ? 'bold' : 'normal',
'font-size': this.isSpecial ? '24px' : '12px'
};
}
ngModel显示和更新属性
使用 ngModel 指令显示数据属性,并在用户进行更改时更新该属性。
- 使用ngModel需要导入FormsModule(从 FormsModule 中导入 ngModel 指令),并将其添加到 NgModule 的 imports 列表中
//src/app/app.module.ts
import { FormsModule } from '@angular/forms';
@NgModule({
imports: [
FormsModule
]
})
export class AppModule { }
- 在 HTML 的
<form>
元素上添加 [(ngModel)] 绑定,并将其设置为等于此属性,这里是 name。
[(ngModel)] 语法只能设置数据绑定属性
<input [(ngModel)]="currentItem.name" id="example-ngModel">
- 如果自定义配置,该表单将属性绑定和事件绑定分开,使用属性绑定来设置属性,并使用事件绑定来响应更改。
<input [ngModel]="currentItem.name" (ngModelChange)="setName($event)" id="example-uppercase">
public currentItem = {
name: 'jie'
}
public setName(val:any):void{
this.currentItem.name = val;
console.log('val==',val)
}
//也可以这样使用,如果setName没有设置值,默认ngModel修改的是currentItem.name的值,如果有设置值,使用setName里的设置值。
<input [(ngModel)]="currentItem.name" (ngModelChange)="setName($event)" id="example-ngModel">
内置结构型指令
结构型指令的职责是 HTML 布局。 它们塑造或重塑 DOM 的结构,这通常是通过添加、移除和操纵它们所附加到的宿主元素来实现的。
常见的内置结构型指令 | 作用 |
---|---|
NgIf | 从模板中创建或销毁子视图 |
NgFor | 为列表中的每个条目重复渲染一个节点 |
NgSwitch | 一组在备用视图之间切换的指令 |
ngIf添加或删除元素
//简写方式:
<app-item-detail *ngIf="isActive" [item]="item"></app-item-detail>
<div *ngIf="!hero" class="name">{{hero.name}}</div>
//实际上等价于:
//*ngIf 指令移到ng-template上,成为绑定在方括号[ngIf]中的属性,div的其余部分移到ng-template内部
<ng-template [ngIf]="hero">
<div class="name">{{hero.name}}</div>
</ng-template>
当表达式isActive为true,NgIf 会把 ItemDetailComponent 添加到 DOM 中。当表达式为false时,NgIf 会从 DOM 中删除ItemDetailComponent 并销毁该组件及其所有子组件,从而释放内存和资源。
Angular 不会创建真正的 元素,只会将
ngFor 条目列表
//简写方式:
<div *ngFor="let hero of heroes; let i=index; let odd=odd; trackBy: trackById" [class.odd]="odd">
({{i}}) {{hero.name}}
</div>
//复写组件视图
<app-item-detail *ngFor="let item of items" [item]="item"></app-item-detail>
//实际上等价于:
//ngFor结构型指令相关的所有内容应用到ng-template;而元素上的所有其他绑定和属性应用到了ng-template中的div元素上。
<ng-template ngFor let-hero [ngForOf]="heroes" let-i="index" let-odd="odd" [ngForTrackBy]="trackById">
<div [class.odd]="odd">({{i}}) {{hero.name}}</div>
</ng-template>
let 关键字会声明一个模板输入变量,你可以在模板中引用该变量。
解析器将 let hero、let i 和 let odd 转换为名为 let-hero、let-i 和 let-odd 的变量。
解析器会将 PascalCase 应用于所有指令,并为它们加上指令的属性名称(例如 ngFor)。比如,ngFor 的输入特性 of 和 trackBy ,会映射为 ngForOf 和 ngForTrackBy 。当 NgFor 指令遍历列表时,它会设置和重置它自己的上下文对象的属性。这些属性可以包括但不限于 index、odd 和一个名为 $implicit 的特殊属性。
Angular 会将 let-hero 设置为上下文的 $implicit 属性的值, NgFor 已经将其初始化为当前正在迭代的英雄。
获取 *ngFor 的 index
在 *ngFor 中,添加一个分号和 let i=index 简写形式。下面的例子中把 index 取到一个名为 i 的变量中,并将其与条目名称一起显示。
- 索引号从零开始
<div *ngFor="let item of items; let i=index">{{i + 1}} - {{item.name}}</div>
<div *ngFor="let item of items;index as i">{{i}}--{{item}}</div>
//报错,由于结构型指令会在 DOM 中添加和删除节点,因此每个元素只能应用一个结构型指令。
<div *ngIf="flag" *ngFor="let item of items;index as i">{{i}}--{{item}}</div>
public flag:boolean = true
public items:any[] = ['a','b','c']
用 *ngFor 的 trackBy 跟踪条目
使用 *ngFor 的 trackBy 属性,Angular 只能更改和重新渲染已更改的条目,而不必重新加载整个条目列表。类似vue框架上for循环得key值的作用。
- 如果没有 trackBy,这些按钮都会触发完全的 DOM 元素替换。
- 有了 trackBy,则只有修改了 id 的按钮才会触发元素替换
// 在简写表达式中,将trackBy设置为trackValue方法
<div *ngFor="let item of items; trackBy: trackValue"></div>
//在组件添加一个方法,该方法返回ngFor应该跟踪的值,这里是item.id,如果浏览器已经渲染过此 id,Angular 就会跟踪它,而不会重新向服务器查询相同的 id。
trackValue(index: number, item: Item): number {
return item.id;
}
ngSwitch
就像 JavaScript 的 switch 语句一样。NgSwitch 会根据切换条件显示几个可能的元素中的一个。Angular 只会将选定的元素放入 DOM。
NgSwitch 是一组指令(共三个):
- NgSwitch —— 一个属性型指令,它更改其伴生指令的行为。
- NgSwitchCase —— 结构型指令,当其绑定值等于开关值时将其元素添加到 DOM 中,而在其不等于开关值时将其绑定值移除。
- NgSwitchDefault —— 结构型指令,当没有选中的 NgSwitchCase 时,将其宿主元素添加到 DOM 中。
<div [ngSwitch]="item.spotStatus">
<span *ngSwitchCase="'yj'"> 一级评分 </span>
<span *ngSwitchCase="'ej'"> 二级评分 </span>
<span *ngSwitchCase="'sj'"> 三级评分 </span>
<span *ngSwitchDefault>暂无评分</span>
</div>
属性型指令
使用属性型指令,可以更改 DOM 元素和 Angular 组件的外观或行为。
应用属性型指令
//Angualr 会创建 HighlightDirective 类的实例,并将 <p> 元素的引用注入到该指令的构造函数中,它会将 <p> 元素的背景样式设置为黄色。
<p appHighlight>Highlight me!</p>
//src/app/highlight.directive.ts
// 从 @angular/core 导入 ElementRef。ElementRef 的 nativeElement 属性会提供对宿主 DOM 元素的直接访问权限
import { Directive, ElementRef } from '@angular/core';
//@Directive() 装饰器的配置属性会指定指令的 CSS 属性选择器 [appHighlight]
@Directive({
selector: '[appHighlight]'
})
export class HighlightDirective {
// 在指令的 constructor() 中添加 ElementRef 以注入对宿主 DOM 元素的引用,该元素就是 appHighlight 的作用目标
constructor(el: ElementRef) {
//向 HighlightDirective 类中添加逻辑,将背景设置为黄色
el.nativeElement.style.backgroundColor = 'yellow';
}
}
处理用户事件
如何检测用户何时将鼠标移入或移出元素以及如何通过设置或清除突出显示颜色来进行响应
//引入HostListener,当指针悬停在 p 元素上时,背景颜色就会出现;而当指针移出时,背景颜色就会消失
import { Directive, ElementRef, HostListener } from '@angular/core';
@Directive({
selector: '[appHighlight]'
})
export class HighlightDirective {
constructor(private el: ElementRef) { }
//添加两个事件处理程序,它们会在鼠标进入或离开时做出响应,每个事件处理程序都带有 @HostListener() 装饰器
//使用 @HostListener() 装饰器,你可以订阅本属性型指令宿主 DOM 元素上的事件
@HostListener('mouseenter') onMouseEnter() {
this.highlight('yellow');
}
@HostListener('mouseleave') onMouseLeave() {
this.highlight('');
}
//处理程序会委托给一个辅助方法 highlight(),该方法会设置宿主 DOM 元素 el 的颜色
private highlight(color: string) {
this.el.nativeElement.style.backgroundColor = color;
}
}
将值传递给属性型指令
//同时应用指令和颜色,通过 appHighlight 指令选择器使用属性绑定,将其设置为 color
<p [appHighlight]="color">Highlight me!</p>
//导入input
import { Directive, ElementRef, HostListener, Input } from '@angular/core';
@Directive({
selector: '[appHighlight]'
})
export class HighlightDirective {
//@Input() 装饰器会将元数据添加到此类,以便让该指令的 appHighlight 属性可用于绑定
@Input() public appHighlight ='';
constructor(private el: ElementRef) { }
//添加两个事件处理程序,它们会在鼠标进入或离开时做出响应,每个事件处理程序都带有 @HostListener() 装饰器
//使用 @HostListener() 装饰器,你可以订阅本属性型指令宿主 DOM 元素上的事件
@HostListener('mouseenter') onMouseEnter() {
this.highlight('yellow');
}
@HostListener('mouseleave') onMouseLeave() {
this.highlight('');
}
//处理程序会委托给一个辅助方法 highlight(),该方法会设置宿主 DOM 元素 el 的颜色
private highlight(color: string) {
this.el.nativeElement.style.backgroundColor = color;
}
}
通过 NgNonBindable 停用 Angular 处理过程
要防止在浏览器中进行表达式求值,请将 ngNonBindable 添加到宿主元素。
- ngNonBindable 会停用模板中的插值、指令和绑定
- 如果将 ngNonBindable 应用于父元素,则 Angular 会禁用该元素的子元素的任何插值和绑定,例如属性绑定或事件绑定。
- 但是,ngNonBindable 仍然允许指令在应用 ngNonBindable 的元素上工作
//结果:This should not evaluate: {{ 1 + 1 }}
<p ngNonBindable>This should not evaluate: {{ 1 + 1 }}</p>
//属性型指令appHighlight可以起作用,表达式{{ 1 + 1 }} 不会求值
<div ngNonBindable [appHighlight]="'yellow'">This should not evaluate: {{ 1 +1 }}, but will highlight yellow.
</div>
创建结构型指令
UnlessDirective 会通过 Angular 生成的 创建一个嵌入的视图,然后将该视图插入到该指令的原始
宿主元素紧后面的视图容器中。
TemplateRef可帮助你获取 的内容,而 ViewContainerRef 可以访问视图容器。
//src/app/unless.directive.ts
//导入 Input、TemplateRef 和 ViewContainerRef
import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';
@Directive({ selector: '[appUnless]'})
export class UnlessDirective {
private hasView = false;
//在指令的构造函数中将 TemplateRef 和 ViewContainerRef 注入成私有变量
constructor(
private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef) { }
//添加一个带 setter 的 @Input() 属性 appUnless
@Input() set appUnless(condition: boolean) {
if (!condition && !this.hasView) {
//如果条件是假值,并且 Angular 以前尚未创建视图,则此 setter 会导致视图容器从模板创建出嵌入式视图
this.viewContainer.createEmbeddedView(this.templateRef);
this.hasView = true;
} else if (condition && this.hasView) {
//如果条件为真值,并且当前正显示着视图,则此 setter 会清除容器,这会导致销毁该视图
this.viewContainer.clear();
this.hasView = false;
}
}
}
使用指令:
*(星号)是将 appUnless 标记为结构型指令的简写形式。
angular 将结构型指令前面的星号转换为围绕宿主元素及其后代的 <ng-template>
。
//condition为true不显示,为false显示
<p *appUnless="condition" class="unless a">123</p>
用<ng-template>
创建模板片段
Angular 的 <ng-template>
元素定义了一个默认情况下不渲染任何内容的模板。
如果没有结构型指令,并且将某些元素包装在 <ng-template>
中,则这些元素会消失。
<p>Hip!</p>
//没有结构指令,不会渲染ng-template包裹的div
<ng-template> <p>Hip!</p></ng-template>
<p>Hooray!</p>