文章目录
组件与模板
用户输入
绑定用户输入事件
@Component({
selector: 'app-click-me',
template: `
<button (click)="onClickMe()">Click me!</button>
{{clickMessage}}`
})
export class ClickMeComponent {
clickMessage = '';
onClickMe() {
this.clickMessage = 'You are my hero!';
}
}
通过 $event 对象取得用户输入(不靠谱)
template: `
<input (keyup)="onKey($event)">
<p>{{values}}</p>
`
export class KeyUpComponent_v1 {
values = '';
// 并非所有的event都有value属性
// onKey(event: any) { // without type info
// this.values += event.target.value + ' | ';
//}
// 建议转化成正确的类型
onKey(event: KeyboardEvent) { // with type info
this.values += (event.target as HTMLInputElement).value + ' | ';
}
}
通过模板引用变量中获得用户输入
@Component({
selector: 'app-key-up2',
template: `
<input #box (keyup)="onKey(box.value)">
<p>{{values}}</p>
`
})
export class KeyUpComponent_v2 {
values = '';
onKey(value: string) {
this.values += value + ' | ';
}
}
在标识符前加上井号 (#) 就能声明一个模板引用变量。注意应该传递该模板变量的value。
回车事件与失焦事件
@Component({
selector: 'app-little-tour',
template: `
<input #newHero
(keyup.enter)="addHero(newHero.value)"
(blur)="addHero(newHero.value); newHero.value='' ">
<button (click)="addHero(newHero.value)">Add</button>
<ul><li *ngFor="let hero of heroes">{{hero}}</li></ul>
`
})
export class LittleTourComponent {
heroes = ['Windstorm', 'Bombasto', 'Magneta', 'Tornado'];
addHero(newHero: string) {
if (newHero) {
this.heroes.push(newHero);
}
}
}
keyup.enter与blur
属性型指令
创建属性型指令
ng generate directive highlight
CLI 会创建 src/app/highlight.directive.ts 及相应的测试文件
使用属性型指令
<p [appHighlight]="color" defaultColor="violet">Highlight me!</p>
export class AppComponent {
color = 'yellow';
}
import { Directive, ElementRef, HostListener, Input } from '@angular/core';
@Directive({
selector: '[appHighlight]'
})
export class HighlightDirective {
constructor(private el: ElementRef) { }
@Input() defaultColor: string;
// 绑定到属性别名
@Input('appHighlight') highlightColor: string;
// @HostListener 装饰器让你订阅某个属性型指令所在的宿主 DOM 元素的事件
@HostListener('mouseenter') onMouseEnter() {
this.highlight(this.highlightColor || this.defaultColor || 'red');
}
@HostListener('mouseleave') onMouseLeave() {
this.highlight(null);
}
private highlight(color: string) {
this.el.nativeElement.style.backgroundColor = color;
}
}
- ElementRef 的 nativeElement 属性可以有直接访问宿主 DOM 元素的能力。
- @HostListener 装饰器让你订阅某个属性型指令所在的宿主 DOM 元素的事件
- 使用 @Input 数据绑定向指令传递值,还可以指定别名,减少属性的数量
- 支持绑定多个属性
注意此处绑定第二个属性时,没有加上[]方括号,此时就传递的是字符串而不是变量了,该点与Vue中的v-bind(:)很类似。
结构型指令
结构型指令的职责是 HTML 布局。 它们塑造或重塑 DOM 的结构,比如添加、移除或维护这些元素。
结构型指令非常容易识别。 在这个例子中,星号(*)被放在指令的属性名之前。
你可以在一个宿主元素上应用多个属性型指令,但只能应用一个结构型指令。
*ngIf
与v-if差不多,
*ngFor
<div *ngFor="let hero of heroes; let i=index; let odd=odd; trackBy: trackById" [class.odd]="odd">
({{i}}) {{hero.name}}
</div>
与v-for用法有些微差别,主要index的获取方式,此处还多了odd(奇数的用法)
模板输入变量与模板引用变量
- 模板输入变量:可以在单个实例的模板中引用它的值。 上个例子中有好几个模板输入变量:hero、i 和 odd。 它们都是用 let 作为前导关键字。
- 模板引用变量:使用的是给变量名加 # 前缀的方式(#var)。 一个引用变量引用的是它所附着到的元素、组件或指令。它可以在整个模板的任意位置访问。
每个宿主元素上只能有一个结构型指令
ngIf与ngFor不能同时作用到一个宿主元素上,这点与v-if和v-for相同,都是通过容器包装下,才能在一起使用。
<ng-template>元素
如果没有使用结构型指令,而仅仅把一些别的元素包装进<ng-template> 中,那些元素就是不可见的。
<p>Hip!</p>
<ng-template>
<p>Hip!</p>
</ng-template>
<p>Hooray!</p>
<ng-container> 的救赎
Angular 的 <ng-container> 是一个分组元素,但它不会污染样式或元素布局,因为 Angular 压根不会把它放进 DOM 中。
<ng-container>解决了根元素显示异常的情况。
<p>
I turned the corner
<ng-container *ngIf="hero">
and saw {{hero.name}}. I waved
</ng-container>
and continued on my way.
</p>
<div>
Pick your favorite hero
(<label><input type="checkbox" checked (change)="showSad = !showSad">show sad</label>)
</div>
<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>
写一个结构型指令(没看懂)
<p>
The condition is currently
<span [ngClass]="{ 'a': !condition, 'b': condition, 'unless': true }">{{condition}}</span>.
<button
(click)="condition = !condition"
[ngClass] = "{ 'a': condition, 'b': !condition }" >
Toggle condition to {{condition ? 'false' : 'true'}}
</button>
</p>
<p *appUnless="condition" class="unless a">
(A) This paragraph is displayed because the condition is false.
</p>
<p *appUnless="!condition" class="unless b">
(B) Although the condition is true,
this paragraph is displayed because appUnless is set to false.
</p>
import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';
/**
* Add the template content to the DOM unless the condition is true.
*/
@Directive({ selector: '[appUnless]'})
export class UnlessDirective {
private hasView = false;
constructor(
private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef) { }
@Input() set appUnless(condition: boolean) {
if (!condition && !this.hasView) {
this.viewContainer.createEmbeddedView(this.templateRef);
this.hasView = true;
} else if (condition && this.hasView) {
this.viewContainer.clear();
this.hasView = false;
}
}
}
把这个指令添加到 AppModule 的 declarations 数组中。