【问题标题】:Nativescript (tap) event on a custom Angular component自定义 Angular 组件上的 Nativescript (tap) 事件
【发布时间】:2020-01-28 17:51:21
【问题描述】:

我正在尝试在 nativescript 中的 custom Angular 组件上绑定(点击)事件。

我创建了一个名为“ns-custom”的自定义组件并尝试将 (tap) 事件绑定到它。但它不起作用。

在自定义组件中我这样做:

<StackLayout>
    <Label text="Title"></Label>
    <Label text="some text"></Label>
</StackLayout>
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'ns-custom',
  templateUrl: './custom.component.html',
  styleUrls: ['./custom.component.css']
})
export class CustomComponent{

  constructor() { }
}

在父元素中我这样做:

<ns-custom (tap)="onCustomComponentClick()"></ns-custom>
    onCustomComponentClick() {
        console.log('custom-component was tapped');
    }

我希望在我点击自定义组件时触发 (tap) 事件,但事实并非如此。我在纯 Angular 中构建了相同的结构,如果将 (click) 事件放入自定义组件,则会触发。

我尝试从自定义组件传播 (tap) 事件,如下所示,但随后它触发了两次(正如预期的那样,因为如果我不使用 event.stopPropagation(),tap 事件将传播到父组件):

<StackLayout (tap)="emitTap()">
    <Label text="Title"></Label>
    <Label text="some text"></Label>
</StackLayout>

@Component({
  selector: 'ns-custom',
  templateUrl: './custom.component.html',
  styleUrls: ['./custom.component.css']
})
export class CustomComponent{
   @Output() tap = new EventEmitter();

   emitTap() {
       this.tap.emit();
   }
}

然后在父组件上捕获事件:

<ns-custom (tap)="onCustomComponentClick()"></ns-custom>
    onCustomComponentClick() {
        console.log('custom-component was tapped');
    }

但是现在点击事件触发了两次。我可以通过将 EventEmitter 名称更改为“tap”以外的名称(例如 @Output() childTapped = new EventEmitter();&lt;ns-custom (childTapped)="onCustomComponentClick()"&gt;&lt;/ns-custom&gt;)或在点击时传递 $event 对象然后使用 event.stopPropagation() 来解决它,但这并不优雅全部。

知道如何以优雅的方式解决这个简单的问题吗?

【问题讨论】:

  • 与 Angular Web 不同,自定义组件上的属性/事件绑定不会自动映射到它的根元素。您必须使用输入/输出装饰器来公开属性/事件。如果您的事件被触发了两次,请分享一个 Playground 示例,以便重现该问题。
  • 我无法在操场上重现这个。我正在使用 tns v5.4,无法升级 ATM。如果子组件和父组件都具有(tap) 绑定,它会发出两次点击。解决这个问题的方法是在自定义子组件上绑定(tap),然后发出一个带有@Output 装饰器的事件,该装饰器命名为tap(比如tap_),以便事件传播具有以下逻辑:自定义组件侦听tap,然后向其父级发出不同的事件tap_,该事件侦听tap_ 事件。这样只有自定义组件的 tap 事件被 angular 拾取并且只触发一次
  • 在这种情况下,您可以设置一个 Git 存储库。
  • 您是否得到任何修复或修复?
  • 您只能通过将点击事件从子组件“冒泡”到父组件来解决此问题,如下所示:在子组件中,设置@Output() tap_ = new EventEmitter(); 和函数emitTap() { this.tap_.emit(); }。在 html 中,将此函数绑定到元素上的点击事件:(tap)="emitTap()。然后,在父元素中,在tap_事件上设置一个事件监听器:(tap_)="doSomethingByParent()",并在父元素的doSomethingByParent() { // ... }中编写你需要的代码。如果需要,您可以在这些事件之间传递 angular 的 $event

标签: nativescript angular2-nativescript


【解决方案1】:

@mick-morely 在 cmets 中基本上回答了这个问题,但我想我会写一个更具描述性的例子,以及为什么我认为这是一种有用的方法。

您基本上需要为您的自定义组件创建一个自定义事件。虽然无法重用tap 事件似乎很乏味,但它实际上可以提高您的代码质量,使其更具描述性。

所以如果我有一个自定义的HoleComponent 描述一个“洞”,它可能看起来像这样:

孔模板

<GridLayout rows="*" columns="*" (tap)="emitTap()">
    <Label row="0" text="A very deep hole"></Label>
</GridLayout>

孔代码

@Output() holeTap = new EventEmitter();

emitTap() {
    this.holeTap.emit();
}

这个Hole 组件可以被这样的父级使用:

父模板

<Hole (holeTap)="onHoleTap()"></Hole>

明确命名事件实际上有助于使代码更具可读性恕我直言。它还迫使开发人员更多地考虑他们正在使用的域,如果您喜欢使用 DDD,这有助于符合普遍存在的语言。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-13
    相关资源
    最近更新 更多