Output 是属性装饰器,用来定义组件内的输出属性。上篇文章介绍了 Input 装饰器的作用,也了解了当应用启动时,Angular 会从根组件开始启动,并解析整棵组件树,数据由上而下流下下一级子组件。今天介绍的 Output 装饰器,是用来实现子组件将信息通过事件的形式通知到父级组件。
输入属性是通过属性绑定实现父组件到子组件的信息传递。
输出属性是实现通过事件绑定实现子组件到父组件的信息传递。
属性绑定呢实现了模块到视图的信息传递[]=""
事件绑定呢实现了视图到模块的信息传递()=""
合起来呢就是我们所说的数据的双向绑定[()]记忆方式:盒子里面装香蕉
没有绕晕吧?
再绕一个概念:EventEmitter
EventEmitter 用来触发自定义事件,具体使用示例如下:
let numberEmitter: EventEmitter<number> = new EventEmitter<number>();
numberEmitter.subscribe((value: number) => console.log(value));
numberEmitter.emit(10);
在 Angular 4 中的 EventEmitter 应用场景是:子指令创建一个 EventEmitter 实例,并将其作为输出属性导出。子指令调用已创建的 EventEmitter 实例中的 emit(payload) 方法来触发一个事件,父指令通过事件绑定 (eventName)
的方式监听该事件,并通过 $event 对象来获取 payload 对象。
具体下面例子来解释:
下面看一段代码:
分N步:
1.编写子组件的模块.ts文件
import {Component, EventEmitter, OnInit, Output} from '@angular/core'; import {last} from "@angular/router/src/utils/collection"; @Component({ selector: 'app-price-quote', templateUrl: './price-quote.component.html', styleUrls: ['./price-quote.component.css'] }) export class PriceQuoteComponent implements OnInit { stockCode:string="ibm"; price:number; // 用Output装饰lastPrice // 如果指定了输出属性的名字那么父组件捕获的事件名称就是找个属性名 // @Output("pricename") // 如果输出属性没有指定属性名字,那么父组件不活事件的名称就是该输出属性所装饰的属性的属性名 @Output() // 在这里对需要传出到组件外的数据定义一个向外发射时间的类EventEmitter,这个类接收一个泛型, // 这个泛型指定了向外发射的数据的类型。这里指定的是向外发射的数据类型为PriceQuote类型的数据 lastPrice:EventEmitter<PriceQuote>=new EventEmitter(); constructor() { setInterval(() => { // 创建一个属性,这个属性的类型是定义好的PriceQuote类型。属性值等于new一个PriceQuote类型的值 let priceQuote:PriceQuote=new PriceQuote(this.stockCode,100*Math.random()); // 当前价格等于一秒钟生成一个价格的最后一个价格 this.price=priceQuote.lastPrice; // 在这里用lastPrice类的emit向外发射一个值,也就是用EventEmitter类的emit方法向外发射一个值,这个方法接受一个值priceQuote,这个值得类型也是PriceQuote this.lastPrice.emit(priceQuote); },1000); } ngOnInit() { } } export class PriceQuote{ constructor(public stockCode:string, public lastPrice:number){ } }2.定义子组件的模板html
<p> 这是报价组件 </p> <div> 股票代码是{{stockCode}},股票当前价格是{{price|number:"2.2-2"}} </div>
3.定义父组件的ts
import { Component } from '@angular/core'; import {PriceQuote} from "./price-quote/price-quote.component"; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { public title:string="父到子"; public kexuan:string="可选"; // 定义一个属性类型为PriceQuote(注意类型一点要注明是和子组件发射出来的数据一样的类型,也就是泛型一样) // 来接收子组件发射除开的数据 priceQuote:PriceQuote=new PriceQuote("",0); // 定义一个方法来接收子组件发射出的事件并获取里面的值,该方法接受一个事件, // 事件名是子组件发射出来的 // 如果子组件没有指定输出属性的名字默认的接受的名字就是发射的事件的属性名, // 如果输出属性设置看属性名,接受的事件名就是找个属性名 priceQuoteHandler(event:PriceQuote){ // 将当前的属性值赋值为接受到的事件 this.priceQuote=event; } }
4.定义父组件的模板html
<!--在组件的入口处通过事件绑定来捕获子组件发射出来的事件--> <!--(lastPrice)="priceQuoteHandler($event)"--> 不理解? 举个例子(click)="go()"绑定了这个click事件的时候当我们点击之后就触发调用go()这个方法, 来执行一系列的操作,只不过click这个事件是封装好在框架里面的我们点击的时候就调用了click这个方法同事触发执行绑定的go()方法 同样的(lastPrice)="priceQuoteHandler($event)"当子组件的emit()事件将lastPrice向外发射也就是说当lastPrice方法被触发的时候 触发执行了priceQuoteHandler()这个方法。 简而言之就是当lastPrice这个方法触发的时候执行触发执行了priceQuoteHandler()。 就好比是click点击的时候触发执行go();不一样的是click方法是封装在框架里面的,而lastPrice是自定义在子组件里面的 //如果子组件的输出属性没有设置属性名,那么这里绑定的事件名就是输出属性所装饰的属性的属性名 <app-price-quote (lastPrice)="priceQuoteHandler($event)"></app-price-quote> 如果子组件的输出属性定义了属性名这里绑定的事件名就是属性名pricename <app-price-quote (pricename)="priceQuoteHandler($event)"></app-price-quote> <div> 这是在报价组件外部,股票代码是{{priceQuote.stockCode}} 股票价格是{{priceQuote.lastPrice |number:"2.2-2"}} </div>
看完不明白?梳理一下:
在子组件里面有一个需要向父组件传出的数据,就需先再子组件用输出属性@Output来装饰一个属性,这个属性类型EventEmitter类,当调用到这个类的emit方法的时候就把这个属性发射出去.
在父组件中用事件绑定来监听子组件发射出来的属性绑定的时间就是子组件中被@Output锁装饰的属性。当子组件向外发射数据的时候,父组件绑定的事件会监听并捕获这个数据。