Angular2 系列教程(四)Attribute directives

今天我们要讲的是ng2的Attribute directives。顾名思义,就是拓展dom属性的指令。这算是指令的第二课了,因为上节课的components实质也是指令。

例子

这个例子共两个指令,第一个是redify指令,能使元素的color属性变红。另外一个直接复制官网的highlight指令,但是我自己做了很多变化,来讲解写法的多样化。

源代码

@Directive

写指令,你需要从'angular2/core'中导入Directive,然后使用@Directive装饰器去装饰一个类:

app/directives.ts

1
2
3
4
5
6
7
8
9
10
11
import {Directive, ElementRef, Renderer} from 'angular2/core';

@Directive({
selector: '[redify]'
})
export class Redify {

constructor(private _element: ElementRef, private renderer: Renderer) {
renderer.setElementStyle(_element.nativeElement, 'color', 'red');
}
}

这段代码做了这些事:

  1. 在装饰器@Directive中定义选择器redify
  2. 在类Redify中的构造函数里面注入ElementRef,来获取当前的dom元素
  3. 同样注入Renderer服务来操作dom,使其color属性为红色

服务是可以注入指令的。Renderer服务提供了多种操作dom样式的方法。

Official docs for ElementRef

Official docs for Renderer

事件监听

如何实现指令的事件监听呢?答案是设置host

src/app/highlight.directive.ts

1
2
3
4
host: {
'(mouseenter)': 'onMouseEnter()',
'(mouseleave)': 'onMouseLeave()'
}

我们在@Directive中设置host元数据,host是个对象,你可以通过host配置指令的事件监听,当事件发生,将触发相应的成员函数。本例子中,设置了鼠标进入和离开两个鼠标事件。并在类中编写相应的成员函数:

src/app/highlight.directive.ts

1
2
onMouseEnter() { this._highlight(this.highlightColor || this._defaultColor); }
onMouseLeave() { this._highlight(null); }

@Input

如果需要向指令中输入什么,那么需要@input这个装饰器,从'angular2/core'中导入Input即可使用:

1
2
3
4
5
6
@Input('myHighlight') highlightColor: string;

private _defaultColor = 'red';
@Input() set defaultColor(colorName:string){
this._defaultColor = colorName || this._defaultColor;
}

上述代码我们做了几件事:

  1. 给成员变量highlightColor,装饰一个@Input('myHighlight'),使其等于从myHighlight输入的属性
  2. 设置一个私有成员变量_defaultColor
  3. defaultColor属性有个setter,可以重写_defaultColor变量,使_defaultColor等于从defaultColor属性输入的值或者其本身默认值

这都什么鬼?没有接触过装饰器的同学可能觉得不舒服。这是es7里面的语法糖,python里面也有,是一种函数式编程。装饰器实质是个函数,可以多个嵌套装饰。

指令的@Input装饰器,有两种写法:

一就是给成员变量加个装饰器:

1
2
@Input('myHighlight') 
highlightColor: string;

代表从myHighlight属性输入的值会赋给成员变量highlightColor

二就是使用set,编写一个函数,重写相关的成员变量,不明白getset 用法的同学可以参考这个:

1
2
3
4
private _defaultColor = 'red';
@Input() set defaultColor(colorName:string){
this._defaultColor = colorName || this._defaultColor;
}

我们来两个替换一下把:

1
2
3
4
5
6
7
private highlightColor:string;
@Input() set myHighlight(colorName:string){
this.highlightColor=colorName
}

@Input('defaultColor')
private _defaultColor = 'red';

仍然可以运行!

使用指令

导入指令的类,然后注入组件的directives[Redify,HighlightDirective],就可以在模板中使用指令了,这跟组件嵌套是一样的。

app/app.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import {Component} from 'angular2/core';
import {bootstrap} from 'angular2/platform/browser';
import {Redify} from './directives';
import {HighlightDirective} from './highlight.directive';

@Component({
selector: "app",
directives:[Redify,HighlightDirective],
template: `
redify:
<p redify >hello,lewis</p>
myHighlight:
<div>
<input type="radio" name="colors" (click)="color='lightgreen'">Green
<input type="radio" name="colors" (click)="color='yellow'">Yellow
<input type="radio" name="colors" (click)="color='cyan'">Cyan
</div>
<p [myHighlight]="color">Highlight me!</p>
<p [myHighlight]="color" [defaultColor]="'violet'">Highlight me too!</p>
`
})
export class App {
constructor() {

}
}

bootstrap(App, [])
.catch(err => console.error(err));

```

我们可以看到`<p redify >hello,lewis</p>`,`redify`指令就是元素的一个属性而已。

而`highlight`则使用了`[]`

```ts
<p [myHighlight]="color">Highlight me!</p>
<p [myHighlight]="color" [defaultColor]="'violet'">Highlight me too!</p>

我们在模板语法里面讲过,[]是单向属性绑定的语法,里面可以是任何hmtl5属性,当然也可以是我们拓展的html属性,即指令。毕竟angular仍然是”旨在拓展html能力”。

[myHighlight]="color"将成员变量color绑定在myHighlight属性中,[defaultColor]="'violet'"defaultColor设置了'violet'的值。


教程示例代码及目录

示例代码:https://github.com/lewis617/angular2-tutorial

目录:http://www.liuyiqi.cn/tags/Angular2/