我们知道angular指令分为结构型和属性型2种,今天就来研究一下自定义属性型指令。
新建一个firstDirective.ts 文件 内容如下
import { Directive, ElementRef, Input } from '@angular/core';
@Directive({'selector':[first]})
export class firstDirective{
constructor(el:ElementRef){
el.style.color = 'pink'
el.style.background = 'green'
}
}
上面我们定义了一个指令,如何调用呢
src/app/app.component.html
<h1>My First Attribute Directive</h1>
<p first>Highlight me!</p>
src/app/app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html'
})
export class AppComponent {
color: string;
}
这个时候我们已经把这个指令应用到了组件上,p标签背景色为绿色,文字是pink色。
结束了吗?没有,还有很重要的一步
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { HighlightDirective } from './highlight.directive';
@NgModule({
imports: [ BrowserModule ],
declarations: [
AppComponent,
HighlightDirective
],
bootstrap: [ AppComponent ]
})
export class AppModule { }
我么需要在模块的 declarations中引入他,这样在该模块下的组件都需要再重新引入了。
就这么简单吗,我们想尝试点难得
src/app/app.component.html
<h1>My First Attribute Directive</h1>
<h4>Pick a highlight color</h4>
<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>
我们把页面改成了这样,这是要干嘛,还有2个指令都加了中括号?
import { Directive, ElementRef, HostListener, Input } from '@angular/core';
@Directive({
selector: '[myHighlight]'
})
export class HighlightDirective {
constructor(private el: ElementRef) { }
//注意这2个位置的@input的写法
@Input() defaultColor: string;
@Input('myHighlight') highlightColor: string;
@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;
}
}
从这里我们又发现了一个有趣的事情 p [myHighlight]="color">Highlight me! /p
指令居然也可以放在中括号里面,这样就可以作为父组件传递过来的值。
@HostListener('mouseenter') 监听组件mouseenter事件,当鼠标移上去的时候,点亮。
需要注意一点的是,如果子组件的属性名与父组件上一致时,@input()括号里面可以不写
接下来我们我们玩点花样,修改一下指令文件
import { Directive, ElementRef, HostListener, Input } from '@angular/core';
@Directive({
selector: 'div[myHighlight]'
})
export class HighlightDirective {
constructor(private el: ElementRef) { }
@Input() defaultColor: string;
@Input('myHighlight') highlightColor: string;
//我们在这里加了一个 ['$event.target'] 这个必须加 不然btn找不到
@HostListener('mouseenter', ['$event.target'])
onMouseEnter(btn: HTMLElement) {
btn.style.color = 'green'
this.highlight(this.highlightColor || this.defaultColor || 'red');
}
@HostListener('mouseleave') onMouseLeave() {
this.highlight(null);
}
private highlight(color: string) {
this.el.nativeElement.style.backgroundColor = color;
}
}
上面我们通过了btn来控制样式,所以有:
btn = this.el.nativeElement 指向的是当前指令的宿主。。。
@Directive({
selector: 'div[myHighlight]'
}) 这个意思是说 这个指令只能用在div标签上
我们再来看一个新鲜的
import { Directive, HostBinding, HostListener } from '@angular/core';
@Directive({
selector: '[exeButtonPress]'
})
export class ExeButtonPress {
@HostBinding('attr.role') role = 'button';
@HostBinding('class.pressed') isPressed: boolean;
@HostListener('mousedown') hasPressed() {
this.isPressed = true;
}
@HostListener('mouseup') hasReleased() {
this.isPressed = false;
}
}
我们又加入了一个新东西 HostBinding,这个东西又是干嘛的呢
1.@HostBinding('attr.role') role = 'button'; 所有的指令宿主元素都会有一个role属性,值为‘button’
2.@HostBinding('class.pressed') isPressed: boolean; 所有宿主元素在按下去的时候会有pressed类
我们来升级一个玩一下,控制dom的显示和隐藏
import {Directive, Input, TemplateRef, ViewContainerRef} from "@angular/core";
@Directive({
selector:'[myUnless]'
})
export class MyUnlessDirective{
//从宿主元素获取myUnless值 注入到newCondition
@Input('myUnless')
set condition(newCondition:boolean){
if(!newCondition){
this.viewContainer.createEmbeddedView(this.templateRef);
console.log(newCondition);
}else {
// 若boolValue为true 删除该宿主元素
this.viewContainer.clear();
console.log("clear");
}
}
constructor(
private templateRef:TemplateRef<any>,
private viewContainer:ViewContainerRef
){}
}
/1
<p *myUnless="boolValue">
false
</p>
//2
<p *myUnless="!boolValue">
true
</p>
如果boolValue是false,那么第一个p就会在Dom中显示
接下来我就原创一个悬浮提示的指令
import { Directive, ElementRef, HostListener, Input } from '@angular/core';
@Directive({
selector: 'div[tooltip]'
})
export class tooltipDirective {
constructor(private el: ElementRef) { }
@Input('myHighlight') highlightColor: string;
//我们在这里加了一个 ['$event.target'] 这个必须加 不然btn找不到
@HostListener('mouseenter', ['$event.target'])
onMouseEnter(btn: HTMLElement) {
btn.style.color = 'green'
let content = btn.getAttribute('content')
let tooltip = document.createElement('div')
tooltip.innerHTML = content
tooltip.style.position = 'absolute'
//需要计算出离父元素左边的距离
let left = (parseInt(btn.style.left) - tooltip.offsetwidth)/2
tooltip.style.left = left + 'px'
btn.appendChild(tooltip)
this.highlight(this.highlightColor || this.defaultColor || 'red');
}
@HostListener('mouseleave') onMouseLeave() {
// 当从宿主元素离开时 直接删除该节点就是
this.el.nativeElement.removeChild(tooltip)
this.highlight(null);
}
private highlight(color: string) {
this.el.nativeElement.style.backgroundColor = color;
}
}
好了,今天指令就讲到这里,大家可以看下好好吸收,下回我会讲angular的路由和表单等。