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'declarevar$: 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(this.input.nativeElement, "input"),
Observable.fromEvent(this.input.nativeElement, "blur"),
Observable.fromEvent(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;
}returnerrors;
}this.model.control.setValidators(fn);
}
}
private get internalValue() {
let val= (this.input.nativeElement).value;if (!val) returnundefined;
val=val.trim();if (val == "") returnundefined;returnval;
}
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;
}returnval;
}
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 = new EventEmitter();
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 的事件,然后在父控件中去实现内部逻辑。
是不是很简单啊。