通过指令这一标记,给dom添加特定的自定义功能,如样式变化、结构调整、事件暴露等
import {Directive} from '@angular/core';
@Directive({
selector: 'my-directive',// 选择器名.class/[attr]/div
providers: [],// 组件及子组件可使用的provider
inputs: ['inputColor'],// 输入到指令中的属性名
outputs: ['onRemove'],// 输出到指令外的事件名
exportAs: '',// 导出名
host: {// 事件代理,相当于在元素上添加上这种字符串
'(mouseover)': 'toLower()'
},
queries: []// 能被注入到组建中的query
})
export class MyDirective { }
改变被选择的元素的属性
<!-- ng2自带指令 -->
<!-- NgStyle -->
<p [style.background]="'blue'">I am green with envy!</p>
<!-- NgClass -->
<div [ngClass]="setClasses()">This div is saveable and special</div>
/*
* 自定义指令
* 给class包含dark-shadow的元素添加黑暗阴影
*/
import { Directive, ElementRef, Renderer } from '@angular/core';
@Directive({
selector: '.dark-shadow'
})
export class DarkShadowDirective {
constructor(el: ElementRef, renderer: Renderer) {
renderer.setElementStyle(el.nativeElement, 'text-shadow',
'0px 0px 4px black');
}
}
改变被选择的元素的结构
<!-- ng2自带指令 -->
<!-- NgIf -->
<div *ngIf="currentHero">Hello, {{currentHero.firstName}}</div>
<!-- NgFor -->
<div *ngFor="let hero of heroes">{{hero.fullName}}</div>
/*
* 自定义指令
* 将元素双倍展示
*/
import { Directive, Input } from '@angular/core';
import { TemplateRef, ViewContainerRef } from '@angular/core';
@Directive({
selector: '[double]'
})
export class DoubleDirective {
constructor(private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef) {
this.viewContainer.createEmbeddedView(this.templateRef);
this.viewContainer.createEmbeddedView(this.templateRef);
}
}
// .className/[attrName]/tagName/混合写法
@Directive({
selector: '[blueBg]:not(p)'
})
选择器:标签名、类名、属性名、:not()
// 写法1.作为@Directive的元数据写入
@Directive({
selector: 'p'
inputs: ['customColor']
})
// 写法2.使用@Input装饰器写入(推荐)
@Directive({
selector: 'p'
})
export class ColorComponent {
@Input() customColor: string;
}
声明一个输入属性,以便我们可以通过属性绑定更新它
// 写法1.作为@Directive的元数据写入
@Directive({
selector: 'p'
outputs: ['onTalk']
})
// 写法2.使用@Output装饰器写入(推荐)
@Directive({
selector: 'p'
})
export class TalkComponent {
@Output() onSay: EventEmitter<any>;
}
声明一个输出属性,以便我们可以通过事件绑定进行订阅
@Directive({
selector: 'div'
providers: [CalcService]
})
指令及子指令可使用的provider(service)
@Directive({
selector: 'div'
exportAs: 'myDiv'
})
指令在模板中的替代名称
queries:能被注入到组建中的query
// queries参数
@Component({
selector: 'my-app',
queries: {
count: new ViewChild(CountComponent)
}
})
// host参数
@Directive({
selector: 'button[counting]',
host: {
'(click)': 'onClick($event.target)'
}
})
拥有模板、样式的指令
import {Component} from '@angular/core';
@Component({
/* 和directive相同的属性 */
selector: 'my-component',
providers: [],
inputs: ['inputColor'],
outputs: ['onRemove'],
exportAs: '',
host: {
'(mouseover)': 'toLower()'
},
queries: [],
/* 不同于directive的属性 */
styleUrls: [],// 样式文件路径数组
styles: ['p {color:white;}'],
template: '<p>Hello World</p>',
templateUrl: '',// 模版文件路径
moduleId: '',// 组件在ES/CommonJS中的moduleId
animations: [],// 定义动画列表
changeDetection: ChangeDetectionStrategy.default,// 变化检测策略
encapsulation: ViewEncapsulation.Native,// 组件样式封装策略,Native/Emulated/None
entryComponents: [],// 会被动态添加的组件
interpolation: ['{{', '}}'],// 插值表达式符号替换
viewProviders: ''// 组件及子视图组件可使用的provider
})
export class MyComponent { }
嵌入内容
类似于Angular 1中的transclude
可以使用select属性选择嵌入的元素
@Component({
selector: 'my-component',
template: `
<div>
<ng-content select="header"></ng-content>
<div style="border: 2px solid purple;">
<ng-content select="p"></ng-content>
</div>
</div>
`
})
class MyComponentElementComponent {}
监听组件各阶段事件
构建view元素
(即模板template中的元素)
构建content元素
(对应于ng1中的transclude)
初始化数据
class ParentElementComponent {
constructor() {}
// 当被绑定的输入属性(@Input)的值发生变化时调用
ngOnChanges(changes: any) {}
// 初始化指令/组件,仅一次
ngOnInit() {}
// 在每个Angular变更检测周期中调用
ngDoCheck() {}
// 当把内容投影进组件之后调用,仅一次
ngAfterContentInit() {}
// 检测内容投影的变化后调用
ngAfterContentChecked() {}
// 初始化完组件视图及其子视图之后调用,仅一次
ngAfterViewInit() {}
// 检测视图及其子视图的变化后调用
ngAfterViewChecked() {}
// 销毁时调用
ngOnDestroy() {}
}
[parent]
ngOnInit
ngDoCheck
ngAfterContentInit
ngAfterContentChecked
ngAfterViewInit
ngAfterViewChecked
[content]
ngOnInit
ngDoCheck
ngAfterContentInit
ngAfterContentChecked
ngAfterViewInit
ngAfterViewChecked
[child]
ngOnInit
ngDoCheck
ngAfterContentInit
ngAfterContentChecked
ngAfterViewInit
ngAfterViewChecked
给组件设置独特的样式
@Component({
selector: 'hero-app',
template: `
<h1>Tour of Heroes</h1>
<hero-app-main [hero]=hero></hero-app-main>
<style>
span { border: 1px solid black;}
</style>`,
styles: ['h1 { font-weight: normal; }'],
styleUrls: ['app/style.css']
})
设置styles或styleUrls元数据
通过 CSS 文件导入
:host-context 宿主上下文
当宿主元素的上下文附和条件时,样式生效
/deep/ 深作用
宿主
Native
使用浏览器原生的 Shadow DOM 实现
样式不进不出、会影响内容投影、子组件
None
不使用视图封装
样式能进能出
@Component({
selector: 'parent-element',
// 设置封装模式
encapsulation: ViewEncapsulation.Emulated
})
赋予组件动画效果
// 添加inactive状态
state('inactive', style({
backgroundColor: '#eee',
color: 'black'
}))
// 添加active状态
state('active', style({
backgroundColor: 'black',
color: 'white'
}))
void表示元素未在视图的状态
内置状态
// 从状态inactive到active时的转场
transition('inactive => active', animate('100ms ease-in')),
// 从状态active到inactive时的转场
transition('active => inactive', animate('100ms ease-out'))
:leave表示出场
内置转场
import {Component, style, state, trigger, animate, transition} from '@angular/core';
@Component({
selector: 'my-app',
animations: [
trigger('heroState', [
state('inactive', style({
backgroundColor: '#eee',
color: 'black'
})),
state('active', style({
backgroundColor: 'black',
color: 'white'
})),
transition('inactive => active', animate('100ms ease-in'))
],
template: `<h1 [@heroState]="state">Hello World</h1>`
})
组件之间传递状态、消息