在 Aurelia 中,是否有一种在 运行 时间换出自定义控件的好方法?

In Aurelia, is there a good way to swap out a custom control at run time?

在 Aurelia 中,有没有一种在 运行 时间换出自定义元素的好方法?

我的用例是一个将在多个地方使用的控件,但用户可能想要更换给定控件的呈现方式和行为方式。我目前有一个从字符串呈现视图的 InlineViewStrategy,但这具有无法控制视图模型中的绑定等的缺点。我可以在 运行 时间选择一个视图模型来使用吗,我可以允许用户注册他们自己构建的新自定义控件来使用而不是默认情况下使用的控件吗?

所以,我正在构建一个网格:

https://github.com/jeremeevans/EspalierJS

单元格正在使用 InlineViewStrategy:

https://github.com/jeremeevans/EspalierJS/blob/master/src/grid/espalier-cell.ts

并且视图在配置中的映射中定义:

https://github.com/jeremeevans/EspalierJS/blob/master/src/grid/espalier-config.ts

这很丑陋,因为它不允许最终用户在足够高的程度上自定义单元格的行为,而且通常会削弱模板。这对性能也不是很好。

我更愿意将自定义控件定义放在那里并允许用户构建一个完整的控件以进入单元格。

我发现通过从使用 Compose 切换到使用缓存视图工厂并从这些视图工厂渲染视图,我能够大大提高性能,尤其是在 IE11 中。

我有一个字符串到 ViewFactory 的静态映射,并根据需要构建视图工厂,然后将视图工厂绑定到单元格视图:

<td colspan="${(!settings.getButtons && $index == (settings.columns.length - 1)) ? 2 : 1}" repeat.for="column of settings.columns & oneTime"> <espalier-cell column.bind="column" view.bind="column.view" record.bind="record"></espalier-cell> </td>

``` 从“./espalier-data-formatter”导入{IEspalierDataFormatter}; 从“./column-definition”导入{IColumnDefinition}; import { bindable, customElement, inject, noView, ViewSlot, ViewFactory, Container } from "aurelia-framework"; 从 "./enums" 导入 { ColumnType };

@customElement("espalier-cell")
@noView()
@inject(ViewSlot, Container)
export class EspalierCell {
  @bindable
  public column: IColumnDefinition<any>;

  @bindable
  public record: any;

  @bindable
  public view: ViewFactory;

  protected data: any;
  private isAttached = false;

  constructor(private viewSlot: ViewSlot, private container: Container) { }

  protected attached() {
    this.isAttached = true;
    this.loadView();
  }

  protected viewChanged() {
    if (this.isAttached) {
      this.loadView();
    }
  }

  private loadView() {
    const propertyValue = this.record[this.column.propertyName];
    this.data = (<IEspalierDataFormatter>this.column.dataFormatter).format(propertyValue, this.record);
    let view = this.view.create(this.container);
    view.bind(this);
    this.viewSlot.add(view);
    this.viewSlot.attached();
  }
}

```