之前泛泛的以tooltip指令展示过如何定义指令,现在详细分解一下:
在实现tooltip指令之前,需要从angular2/core里面导入一堆东西:
解释几个类:
ElementRef:这个类可以用来在宿主标签里面注入其他标签的引用(不仅仅局限于DOM)。
Directive:对于自己定义的新指令,可以用这个装饰器来添加一些额外的元数据。
HostListener(eventname):这是一个方法装饰器,参数是事件名。在指令实例化的时候,angular2会把这个装饰过的方法当成宿主标签上对应eventname的事件处理函数。
@Directive({
selector: '[saTooltip]'
})
export class Tooltip {
@Input()//用@Input装饰器声明指令的输入
saTooltip:string;
constructor(private el: ElementRef, private overlay: Overlay) {
this.overlay.attach(el.nativeElement);
}
@HostListener('mouseenter')
onMouseEnter() {
this.overlay.open(this.el, this.saTooltip);
}
@HostListener('mouseleave')
onMouseLeave() {
this.overlay.close();
}
}
@input这行代码背后的含义是:给指令定义一个saTooltip属性,属性的值是指定表达式的执行结果,表达式定义在标签的saTooltip属性上。
@input装饰器可以接收一个参数---需要绑定的属性名。如果我们不传递参数,angular默认会自动绑定到同名属性上。
构造函数contructor里面声明了两个私有属性:el和overlay,类型分别为ElementRef和Overlay.Overlay类里面实现了维护tooltip组件外观的逻辑,并且可以用angular的DI机制进行注入,为了让这个属性支持注入,需要这样来定义顶层的组件:
@Component({
selector: 'app',
templateUrl: './app.html',
providers: [Overlay],//支持属性注入
directives: [Tooltip]
})
class App {}
在上面的@Component装饰器中,传递了一个字面量作为参数,这个参数里面带有一个directives属性,这个属性是一个数组,其中包含了整个组件内部以及下面任意层级上的所有子组件会用到的全部指令。
在angular2中,每个组件所用到的所有指令都必须显式进行声明,通过这种方式我们就可以为每一个组件子树创建独立的命名空间。对于特定的指令,只要顺着组件的继承树逐层向上,找到每个组件上的@Component装饰器,然后把每一层上的所有directive数组都合并起来,这样就可以获得所有需要使用的指令了。考虑到所有Component都是Directive的子类,所以指令内部如果嵌套使用了其他指令,也需要显式声明。