Input相當於指令的值綁定,無論是單向的(@)還是雙向的(=)。丟失將父作用域的值“輸入”到子作用域中, 然后子作用域進行相關處理。
Output 相當於指令的方法綁定,子作用域觸發事件執行響應函數, 而響應函數方法體則位於父作用域中, 相當於將事件“輸出”到父作用域中, 在父作用域中處理。
看個angular2示例吧,我們自定義一個numberInput component,獲取父作用域的值或者屬性,然后在鼠標離開的時候調用父組件的方法驗證
import { Component, Input, Output, OnInit, ExistingProvider, forwardRef, AfterViewInit, ElementRef, ViewChild, ViewContainerRef, ChangeDetectorRef, Optional, EventEmitter } from '@angular/core' import { NgModel, ControlValueAccessor, NG_VALUE_ACCESSOR, NgForm, FormControl, ValidatorFn, ValidationErrors } from '@angular/forms' import { InputBase, existingProvider } from '../../inputBase' import { Observable } from 'rxjs' declare var $: any; @Component({ selector: 'cm-number', templateUrl: 'numberInput.component.html', styleUrls: ["./numberInput.component.css"], providers: [existingProvider(NumericInputComponent)] }) export class NumericInputComponent extends InputBase implements OnInit { @ViewChild("input") input: ElementRef; ngOnInit() { Observable.merge( Observable.fromEvent<Event>(this.input.nativeElement, "input"), Observable.fromEvent<Event>(this.input.nativeElement, "blur"), Observable.fromEvent<Event>(this.input.nativeElement, "change") ).subscribe(e => { e.stopPropagation(); e.stopImmediatePropagation(); let p = e.target as HTMLInputElement; let val = this.format(p.value); if (val !== p.value) { p.value = val; } if (val != this.model.value) { if (val == undefined || val.trim() === "") { this.onChange(undefined); } else { this.onChange(parseFloat(val)); } } }); if (this.model != null) { var fn: ValidatorFn = (c) => { var errors: ValidationErrors = {}; if ((this.hasEqualOperatorForMin && parseFloat(this.internalValue) < parseFloat(this.min.toString())) || (!this.hasEqualOperatorForMin && parseFloat(this.internalValue) <= parseFloat(this.min.toString())) || parseFloat(this.internalValue) > parseFloat(this.max.toString())) { errors.dose = true; } return errors; } this.model.control.setValidators(fn); } } private get internalValue() { let val = (<HTMLInputElement>this.input.nativeElement).value; if (!val) return undefined; val = val.trim(); if (val == "") return undefined; return val; } private format(val: string) { while (true) { let newVal = val.replace(/[^0-9.-]/g, ''); if (this.allowFloat) { newVal = newVal.replace(/(\..*)\./g, '$1'); } else { newVal = newVal.replace(/(.*)\./g, '$1'); } if (!this.allowNegative) { newVal = newVal.replace(/-/g, ''); } else { newVal = newVal.replace(/^-(-.*)/g, '$1'); newVal = newVal.replace(/(.+)-/g, '$1'); } newVal = newVal.replace(/^0+([0-9].*)/g, '$1'); newVal = newVal.replace(/^0+(0\..*)/g, '$1'); if (newVal === val) break; val = newVal; } return val; } public _value: string; @Input() maxlength: number; @Input() readonly: boolean = false; @Input() allowFloat: boolean = true; @Input() min: number = 0; @Input() max: number = 99999; @Input() public get value() { return this._value; } public set value(val: string) { this._value = val; if (val == undefined || val.trim() == "") { this.onChange(undefined); } else { this.onChange(parseFloat(this._value)); } } public writeValue(obj: any) { obj = obj == undefined ? "" : obj; (this.input.nativeElement as HTMLInputElement).value = obj; } @Output() public onblur: EventEmitter<any> = new EventEmitter<any>(); blur(e: Event) { this.onblur.emit($(e.target).val()); } }
就舉一個例子:
我們在父作用域中使用的時候, 可以這樣賦值:
其實number input component 中, 我們會根據 allowFloat 的值,來決定是否允許輸入小數。
ok, 以上是Input的示例。
Output一般都是一個EventEmitter的實例,使用實例的emit方法將參數emit到父組件中,觸發父組件的事件。
然后父組件監聽到該事件的發生,執行對應的處理函數。
這里之所以要自定義一次 blur 事件(EventEmitter), 是因為在 ngOnInit()中已經對blur 事件做過處理,這樣父控件中就會被阻止掉,如果父控件中要用到blur 事件的話, 就可以用這種方式來做,我們自定義一個叫onBlur 的事件,然后在父控件中去實現內部邏輯。
是不是很簡單啊。