Angular2 @Component

Directive/指令

通过指令这一标记,给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 { }

属性型指令

改变被选择的元素的属性

Example:

<!-- 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');
    }
}

结构型指令

改变被选择的元素的结构

Example:

<!-- 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);
  }
}

@Directive参数详解

// .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'
})

指令在模板中的替代名称

其他

  • host:事件代理,使用后将在元素上添加对应属性
  • queries:能被注入到组建中的query

// queries参数
@Component({
  selector: 'my-app',
  queries: {
    count: new ViewChild(CountComponent)
  }
})
// host参数
@Directive({
  selector: 'button[counting]',
  host: {
    '(click)': 'onClick($event.target)'
  }
})

Component/组件

拥有模板、样式的指令

使用方法

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 { }

ngContent

嵌入内容

  1. 将内容嵌入到组件模板中
  2. 类似于Angular 1中的transclude

  3. 可以使用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']
})
  • 内联在模板的 HTML
  • 设置stylesstyleUrls元数据

  • 通过 CSS 文件导入

特殊选择器

  • :host宿主元素选择器
    • 直接作用于宿主元素 
  • :host-context 宿主上下文

    • 当宿主元素的上下文附和条件时,样式生效

  • /deep/ 深作用

宿主

视图封装模式

  • Emulated(默认)
    • 通过预处理(并改名)CSS 代码来模拟 Shadow DOM 的行为
    • 样式只进不出,不会影响内容投影、子组件
  • 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'))
  • :enter表示进场
  • :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>`
})

组件通讯

组件之间传递状态、消息

@input/@output

  • 通过输入型绑定,把数据从父组件传到子组件
  • 通过输出型绑定,使父组件监听子组件事件

ngOnChanges

  • 当输入型数据改变时,会调用生命周期中的ngOnChanges方法
  • 此方法返回所有改变的数据值

本地变量与ViewChild

  • 本地变量:在模板中访问
  • ViewChild:在代码中访问

Service

  • 创建一个单例service
  • 父组件和子组件共享同一个service
  • 通过监听service的变化来实现组件之间的通讯

The End-Q&A

  • Directive
    • 属性型指令
    • 结构型指令
    • 参数详解
  • Component
    • ngContent
    • 生命周期
    • 组件样式
    • 组件动画
    • 组件通讯

angular2-component

By leegend

angular2-component

  • 304