【问题标题】:Aurelia custom element bubbling/delegating from within a function?Aurelia 自定义元素从函数中冒泡/委托?
【发布时间】:2018-06-06 12:38:43
【问题描述】:

我有一个自定义元素,它在跨度中显示一些文本,如果用户决定编辑文本,我会隐藏跨度并显示文本输入。 当用户关注文本输入时,我隐藏输入并使用更新的文本再次显示跨度。 这一切都很好。

当我在页面上使用自定义元素时,我需要能够在页面上触发一个函数,以从自定义元素中获取更新的文本来更新数据库中的文本。

当用户完成文本编辑并重新显示跨度时,我不知道如何冒泡该事件,因此我可以调用页面上的函数来保存更改。 如果我使用的是按钮或其他东西,我可以设置按钮单击的委托,但由于我没有使用按钮,因此不知道如何实现。

希望这是有道理的!提前致谢!

这里是一些精简的代码。

custom-element.html:

<i if.bind="icon" class="${icon}"></i><span if.bind="!(allowEditTitle && isEditingTitle)" maxlength>${title}</span>
<input ref="titleInputEditor" type="text" value.bind="title" if.bind="allowEditTitle && isEditingTitle" maxlength="100" />

custom-element.ts

@bindable title: string;
@bindable allowEditTitle: boolean = false;
isEditingTitle: boolean = false;

toggleEditTitle() {
    let me = this;
    if (this.allowEditTitle === true) {
        this.isEditingTitle = !this.isEditingTitle;
    }
    if (this.isEditingTitle == true) {
        window.setTimeout(function () {
            $(me.titleInputEditor).focus();
            $(me.titleInputEditor).select();
            $(window).one('click', function () {
                if (me.isEditingTitle == true) {
                    me.toggleEditTitle();
                } 
            });
            $(me.titleInputEditor).one('click', function (e) {
                e.stopPropagation();
            });
            $(me.titleInputEditor).one('focusout', function () {
                me.toggleEditTitle();
            });
        });
    }
}

app.html

<custom-element title="Default Text" 
        allow-edit-title.bind="true" 
        on-???????.call="saveTextFunction">
</custom-element>

【问题讨论】:

    标签: typescript events delegates aurelia


    【解决方案1】:

    您可以使用aurelia-event-aggregator 来完成此操作。您可以在 focusout 上发布一个事件,然后在代码中的其他位置(很可能是某处的服务)订阅该事件,这将更新您的数据库。


    custom-element.ts

    import { autoinject, EventAggregator } from "aurelia-framework";
    
    @autoinject
    export class CustomElement {
      constructor(private ea: EventAggregator)
    
    
    ...
    
            $(me.titleInputEditor).one('focusout', function () {
                me.ea.publish('input-changed', me.title);
                me.toggleEditTitle();
            });
    ...
    }
    

    service.ts

    import { autoinject, EventAggregator } from "aurelia-framework";
    
    @autoinject
    export class Service {
      constructor(private ea: EventAggregator)
    
      public attached() {
        this.ea.subscribe('input-changed', (value) => {
           // update database using value
        });
      }
    }
    

    有关事件聚合器的更多文档,请参阅here

    【讨论】:

    • EventAggregator 正是我想要的!
    【解决方案2】:

    据我所知,您尝试绑定一个函数。 .call 绑定就完成了,没错。

    将@bindable 属性添加到您的自定义元素并从适当的位置调用它

    @binable onUpdateChanges: Function;
    updateText(){
       if(this.onUpdateChanges)
          this.onUpdateChanges();
    }
    

    在 app.html 中这样绑定:

    <custom-element title="Default Text" 
        allow-edit-title.bind="true" 
        on-update-changes.call="saveTextFunction()">
    </custom-element>
    

    在 app.ts 中添加 saveTextFunction

    saveTextFunction(){
          //Do stuff to update/save/persist something
    }
    

    如果你想传递参数,你需要在你的自定义元素中注册 onUpdateChanges 略有不同

    custom-element.ts

    updateText(){
       if(this.onUpdateChanges)
          this.onUpdateChanges({text: what_ever_value_you_want_to_pass});
    }
    

    app.html

    <custom-element title="Default Text" 
        allow-edit-title.bind="true" 
        on-update-changes.call="saveTextFunction(text)">
    </custom-element>
    

    app.ts

     saveTextFunction(text:string){
          //Do stuff to update/save/persist something
    }
    

    【讨论】:

      【解决方案3】:

      如果您需要在位于应用程序中任意位置的两个元素之间传递信息(例如“冒泡”并不总是有效),那么 Jesse 的答案 (EventAggregator) 是您的最佳选择

      Schadensbegrenzer 的回答也适用于您的特定情况,但我个人认为通过可绑定传递函数更意味着将行为动态传递给自定义元素,而不是跨元素通信。

      在你的情况下我会做的实际上是让事件冒泡。您可以使用CustomEvent 来完成此操作,如下所示:

      custom-element.ts

      $(me.titleInputEditor).one('focusout', function () {
          // it'd be slightly cleaner to inject `Element` in your CustomElement
          // and dispatch this event on that element instead
          me.titleInputEditor.dispatchEvent(new CustomEvent('input-changed', {
              detail: me, // if you want to pass this CustomElement instance up to the listener
              bubbles: true
          }));
          me.toggleEditTitle();
      });
      

      app.html

      <custom-element title="Default Text" 
              allow-edit-title.bind="true" 
              input-changed.delegate="saveTextFunction">
      </custom-element>
      

      【讨论】:

      • 我不完全同意。传递函数并不是传递行为。它更像是子自定义组件在发生特定情况时可以调用的电话号码。事实上你也在做同样的事情:onFocusOut 调用父级。我同意如果组件处于任意位置并且可能无法直接通信,则应该使用 EventAggregator。或者使用事件聚合器来广播消息。但在这种情况下,自定义组件必须能够与其父级通信,所以我宁愿选择我的或你的解决方案。但是,最后所有 3 种解决方案都有效。 :-)
      • 事后看来,这是一个糟糕的措辞选择。考虑语义:您正在收听一个事件,并且您想要进一步向上传递该事件进行直接的一对一映射。在这种情况下,调度 CustomEvent(在我看来)是最“自然”的解决方案。该事件将冒泡到树中的任何级别。当这种 1 对 1 映射不太明显时,或者当元素可以通过绑定轻松访问彼此时,函数调用可能是更简洁的解决方案。更少的代码行来实现同样的事情,但更难重构。所以这取决于。您的解决方案确实可以更好。
      猜你喜欢
      • 1970-01-01
      • 2012-02-26
      • 1970-01-01
      • 2015-08-07
      • 1970-01-01
      • 1970-01-01
      • 2015-09-22
      • 2018-03-27
      • 2017-01-01
      相关资源
      最近更新 更多