【问题标题】:Input vs Output Event Binding输入与输出事件绑定
【发布时间】:2018-06-02 03:55:46
【问题描述】:

我正在寻找一个论据,说明为什么在事件中使用 @Output 比在 Angular 2+ 中传递 @Input 函数更好。

使用@Input:

父模板:

<my-component [customEventFunction]=myFunction></my-component>

在 parent-component.ts 中:

myFunction = () => {
  console.log("Hello world")
}

在 my-component.ts 中

@Input() customEventFunction: Function;

someFunctionThatTriggersTheEvent() {
  this.customEventFunction();
}

使用@Output

父模板:

<my-component (onCustomEvent)=myFunction()></my-component>

在 parent-component.ts 中:

myFunction() {
  console.log("Hello world")
}

在 my-component.ts 中

@Output() onCustomEvent: EventEmitter<any> = new EventEmitter<any>();

someFunctionThatTriggersTheEvent() {
  this.onCustomEvent.emit();
}

两者都实现了相同的目标,但我认为 @Output 方法比我在其他 Angular 包中看到的更典型。有人可能会争辩说,使用 Input,您可以检查该函数是否存在,如果该事件仅应有条件地触发。

想法?

【问题讨论】:

  • 这里有什么问题?
  • 为什么要使用输出而不是输入进行事件绑定,反之亦然?
  • 一个原因是许多订阅者可以处理 Output 事件,而只能为 Input 属性提供一个处理程序。
  • @ConnorsFan 嗯,我没想到。如果您愿意,我很乐意接受这个作为答案,但需要更详细一点。

标签: angular typescript angular2-components angular5 typescript-decorator


【解决方案1】:

@Output 事件绑定的优点:

  1. 使用 @Output 定义事件清楚地表明它期望回调方法使用标准 Angular 机制和语法来处理事件。
  2. 许多事件处理程序可以订阅@Ouptut 事件。另一方面,如果定义一个接受回调函数的@Input 属性,则只能注册一个事件处理程序;分配第二个事件处理程序将断开第一个事件处理程序。为了与标准 DOM 事件处理程序并行,@Input 回调函数绑定类似于设置onmousemove="doSomething()",而@Output 事件绑定更像是调用btn.addEventListener("mousemove", ...)

【讨论】:

    【解决方案2】:

    @Sajeetharan 的回答实际上并不完全正确: 存在显着的功能差异:执行上下文。考虑这种情况:

    @Component({
      selector: 'app-example',
      template: `<button (click)="runFn()">Click Me</button>`,
    })
    export class ExampleComponent {
      @Input() public fn: any;
    
      public runFn(): void {
        this.fn();
      }
    }
    
    @Component({
      selector: 'app',
      template: `<app-example [fn]="myFn"></app-example>`,
    })
    export class AppComponent {
      public state = 42;
    
      // Using arrow syntax actually *will* alert "42" because
      // arrow functions do not have their own "this" context.
      //
      // public myFn = () => window.alert(this.state);
    
      public myFn(): void {
        // Oops, this will alert "undefined" because this function
        // is actually executed in the scope of the child component!
        window.alert(this.state);
      }
    }
    

    这实际上使得使用@Input() 属性传递函数变得非常尴尬。至少它打破了最小惊喜的原则,并且可以引入鬼鬼祟祟的错误。

    当然,在某些情况下您可能不需要上下文。例如,也许您有一个可搜索的列表组件,它允许将复杂数据作为项目,并且需要传递一个fnEquals 函数,以便搜索可以确定搜索输入文本是否与项目匹配。但是,这些情况通常可以通过更可组合的机制(内容投影等)更好地处理,从而提高可重用性。

    【讨论】:

    • 感谢您的回答!我们在应用程序的几个地方使用了@Input 事件绑定,但我无法弄清楚为什么箭头函数对于范围是必需的。我能问为什么,因为箭头函数没有“this”上下文,它们可以访问父组件而不是子组件的上下文吗?
    • 箭头函数没有定义自己的“this”意味着它们从封闭的执行上下文中获取它,这是它们被定义的地方并且独立于它们的调用方式(普通函数可以绑定到特定的“这”)。 MDN 关于箭头函数的文章的描述部分对此进行了详细讨论。
    【解决方案3】:

    功能上基本有no differences,但是

    (i)当您使用 @input 时,您使用 @Input 的优势在于我们可以定义类型以及它是私有的还是公共的 p>

    (ii)正如评论中提到的@ConnorsFan,使用@Ouput的好处是可以有多个订阅者处理Output事件,而只能处理一个处理程序为 @Input 属性提供。

    【讨论】:

      猜你喜欢
      • 2021-10-02
      • 1970-01-01
      • 1970-01-01
      • 2018-06-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-20
      • 1970-01-01
      相关资源
      最近更新 更多