Aurelia:在顶级声明自定义元素并跨应用程序访问

Aurelia: Declaring custom element at top-level and access across application

我有一个名为 loading-bar 的自定义元素,它在我的应用程序的多个页面中使用。它的目的是在加载、下载内容时显示状态消息,并为后端操作提供响应消息。

加载中-bar.html:

<template show.bind="visible">
    <i class="fa fa-circle-o-notch fa-spin fa-fw" if.bind="type==1"></i>
    <i class="fa fa-check fa-fw" if.bind="type==2"></i>
    <span id="loading-text">${message}</span>
</template>

加载中-bar.ts:

import { customElement, bindable, bindingMode, inject } from 'aurelia-framework';

@customElement('loading-bar')
export class LoadingBarCustomElement {
    private visible = false;
    @bindable({ defaultBindingMode: bindingMode.twoWay }) message;
    @bindable({ defaultBindingMode: bindingMode.twoWay }) type = 1;


    constructor() {
        this.visible = false;
    }

    messageChanged(newValue, oldValue) {
        if (newValue && newValue !== '')
            this.visible = true;
        else
            this.visible = false;
    }
}

目前所有使用加载栏的页面都在其 html 中声明了此元素:

<loading-bar message.bind="loadMsg" type.bind="loadType"></loading-bar>

loading-Bar通过改变每个页面的loadMsg和loadType局部变量来控制。

我想做的是在适当的地方声明加载栏 html,并且能够(从任何页面)调用像 "showBar(msg, type)" 这样的方法,这将影响全局声明的加载栏。

我首先要在 app.html 中声明加载栏(就像我在此处声明的导航栏一样)并注入一个 class(在所有页面的 ViewModel 中),其中包含控制加载栏的 showBar(msg, type) 方法。

我不确定这是否是正确的前进方式,或者它的最佳实施方式,希望能提供一些帮助。

决定这样解决:

<loading-bar message.bind="lbc.loadMsg" type.bind="lbc.loadType"></loading-bar>

已添加到 app.html

创建了一个控制器class,它将用作单例:

export class LoadingBarController {
    private loadMsg = '';
    private loadType = 1;

    public showBar(message, type) {
        this.loadType = type;
        this.loadMsg = message;
    }
    public hideBar() {
        this.loadMsg = '';
    }
}

这是在 app.ts(别名 "lbc")中注入的,它实际上连接到加载栏元素,并注入到要使用加载栏的页面的每个 viewModel 中. 然后通过注入的控制器控制加载栏,如下所示:

@inject(LoadingBarController)
export class ExamplePage {
    constructor(private lbc: LoadingBarController){
    ...
    }

    methodUsingTheLoadingBar(){
        ...
        this.lbc.ShowBar('Loading...', 1);
        ...
        ...
        this.lbc.HideBar();
    }
}

您可以使用 EventAggregator 来启用您想要执行的操作。

加载中-bar.ts

import { customElement, bindable, bindingMode, autoinject } from 'aurelia-framework';
import { EventAggregator, Subscription } from 'aurelia-event-aggregator';

@customElement('loading-bar')
@autoinject()
export class LoadingBarCustomElement {
    private visible = false;
    private sub1: Subscription;
    private sub2: Subscription;
    @bindable({ defaultBindingMode: bindingMode.twoWay }) message;
    @bindable({ defaultBindingMode: bindingMode.twoWay }) type = 1;


    constructor(private ea : EventAggregator ) {
        this.ea = ea;
        this.visible = false;
    }

    attached() {
      this.sub1 = this.ea.subscribe('show-loading', ({ message, type }) => {
        this.type = type;
        this.message = message;
      });

      this.sub2 = this.ea.subscribe('hide-loading', () => {
        this.message = '';
      });
    }

    detached() {
      this.sub1.dispose();
      this.sub2.dispose();
    }           

    messageChanged(newValue, oldValue) {
        if (newValue && newValue !== '')
            this.visible = true;
        else
            this.visible = false;
    }
}

然后像这样在您的应用中的其他地方发布事件:

import {autoinject} from 'aurelia-framework';
import {EventAggregator} from 'aurelia-event-aggregator';

@autoinject()
export class ExamplePage {
    constructor(private ea: EventAggregator){
    ...
    }

    async methodUsingTheLoadingBar(){
        ...
        this.ea.publish( 'show-loading, { message: 'Loading...', type: 1 });
        const foo = await getData();
        ...
        ...
        this.ea.publish('hide-loading');
    }
}