了解Angular的@Input()和@Output()

首先/起初/最初

有时候在业务中遇到需要实施防止多次点击按钮的解决方案的情况。因此我想着制作一个像魔法一样的按钮组件,通过使用这个组件来实现按钮,它可以自动在内部执行这种防止多次点击的策略。但是我试图实现的方法被认为是反模式,所以放弃了。
虽然有人说我只是浪费了时间,但事实并非如此,多亏了这个,我能够理解Angular中的@Input()和@Output()概念。因此,我希望能在本文中分享我对这些概念的理解和记录。

请留意以下事项

在这个例子中,我们使用了Angular-material。
另外,我们将省略在app.module.ts中声明模块的部分。

@Input()和@Output()代表了什么意思?

首先,我将简要解释这些的作用。
首先,@Input()的作用是从父组件传递值给子组件。
而@Output()的作用是从子组件传递事件(值)给父组件。

尝试用代码深入理解。

这次我们将以一个简单的按钮组件示例来解释。
首先我们看一下组件之间的父子关系。在这个例子中,调用按钮组件的那一方(比如app.component)就是父组件,而按钮组件则是子组件。

请提供输入。

按钮组件

import { Component, Input } from '@angular/core';

@Component({
  selector: 'app-amazing-button',
  templateUrl: './amazing-button.component.html',
  styleUrls: ['./amazing-button.component.css']
})
export class AmazingButtonComponent {

    @Input() buttonText: string = 'BUTTON';
    @Input() buttonColor: string = '';

    constructor() { }

}
<button mat-raised-button color="buttonColor">{{buttonText}}</button>

在按钮组件中,我们声明了@Input() buttonText和@Input() buttonColor。它们分别用于指定按钮的名称和颜色。

通过声明@Input()修饰的变量,我们可以将此组件作为属性从父组件调用,并将值存储在该属性中,以实现从父级到子级的值传递。

首先不指定,我们尝试从父组件调用子组件。

<app-amazing-button></app-amazing-button>
angular-material-button1.JPG

这次尝试将buttonText作为属性进行指定…

<app-amazing-button buttonText="!!AmazingButton!!"></app-amazing-button>
angular-material-button2.JPG
<app-amazing-button buttonText="!!AmazingButton!!" buttonColor="accent"></app-amazing-button>
angularbutton3.JPG

在以下情况下,@Input()用于从父组件向子组件传递值。

@Output()装饰器

我们将继续使用”继续”按钮组件。

按钮组件

import { Component, EventEmitter, Input, Output } from '@angular/core';

@Component({
  selector: 'app-amazing-button',
  templateUrl: './amazing-button.component.html',
  styleUrls: ['./amazing-button.component.css']
})
export class AmazingButtonComponent {

    @Input() buttonText: string = 'BUTTON';
    @Input() buttonColor: string = '';

    @Output() addOops: EventEmitter<string> = new EventEmitter(); // 追加

    constructor() { }

    /**
     * 追加
     */
    sendText() {
        this.addOops.emit('Oops!');
    }

}
<!--clickイベントを追加-->
<button mat-raised-button color="{{buttonColor}}" (click)="sendText()">{{buttonText}}</button>

我已经使用@Output()和点击事件sendText()实现了addOops这个功能。
在声明@Output()时,要实例化EventEmitter。
被声明为@Output()的变量本身就是一个由父组件使用的事件,并通过接收在该事件中发出的值来实现从子组件到父组件的值传递。

在我们开始解释实际操作之前,让我们也把家长方面的实施考虑进去。

<!--子コンポーネントのイベントを追加-->
<app-amazing-button buttonText="!!AmazingButton!!" buttonColor="accent" (addOops)="logMessage($event)"></app-amazing-button>
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {

    /**
     * 追加
     */
    logMessage(text: string) {
        console.log(`${text}, Hello Angular!`);
    }
}

在父组件中,您可以使用子组件中声明为@Output()的变量作为事件。
这是在app.component.html中的(addOops)=~部分。
当点击此按钮时,首先触发子组件中声明的事件。
在这种情况下,对应的事件是amazing-button.component的(click)事件。

  sendText() {
      this.addOops.emit('Oops!');
  }

当调用名为emit()的函数时,它会将值传递给调用其父函数的地方。您可以将要传递的值作为参数传入。

子组件已经传递了值。在父组件中接收这个值的方式是。

(addOops)="logMessage($event)

子コンポーネントのイベントを受け取ることが可能になります。

  logMessage(text: string) {
      console.log(`${text}, Hello Angular!`);
  }

当我们在组件中传递一个名为text的参数时,子组件传递的值将被赋给text,以便在父组件中使用。当我们尝试运行时,我们可以看到效果。

Oops!, Hello Angular!

并在控制台上显示。

顺便提一下,在 @Output() 中,可以使用 emit() 将数据返回为一个对象,可以返回多个数据。

尽管变得冗长了,但归纳一下@Output()的流程如下。

    1. 子组件的事件触发。

 

    1. 在子组件的处理中进行emit()。

 

    在父组件中使用$event接收。

這是如此。

就像这样,@Output()用于将事件(值)从子组件传递给父组件。

顺便提一下

虽然@Input()、@Output()会经常被使用,但也存在着反模式。
关于反模式的详情请见这里。

Angular2的反模式集合
当使用@Input绑定对象时,会遇到各种问题【ionic】【Angular】
将对象作为@Input绑定

看起来对象将成为引用传递的方式。可能会导致意想不到的行为…。

我本来想把回调函数作为@Input()传递,但这是一个反模式?
虽然还有一种方法可以做到…
为了避免陷入回调地狱,还是不这样做为好。
Angular 2:使用事件与回调进行组件通信

最后

这个@Input()和@Output()是非常方便的功能,希望大家一定要理解。

rikaisita.png

闲聊

在Qiita上使用“@”符号会形成对账户的链接,所以有点麻烦。

请提供相关链接。

理解 Angular 的 @Output
Angular2 的反模式集
使用 @Input 绑定对象时会遇到多种问题 【Angular】
使用 @Input 绑定对象
Angular 2:使用事件与回调进行组件通信
参考阅读相关书籍…
Angular 应用程序编程

广告
将在 10 秒后关闭
bannerAds