【问题标题】:Aurelia: Inheritance of view and view-modelAurelia:视图和视图模型的继承
【发布时间】:2019-01-27 18:24:38
【问题描述】:

我正在构建一个 Aurelia 应用程序,它基本上允许用户为不同的资源显示不同的列表。这些列表共享一些功能,例如具有搜索和刷新功能的工具栏以及资源的分页列表。

我为单个资源创建了这个,一切都像一个魅力,但我现在需要为其他资源列表复制 TypeScript 代码和 HTML 的大部分。我决定采用不同的方法,使用一些命名的视图槽和一个抽象的视图模型创建一个自定义元素。这在第一次运行时有效,但在操作列表后它会立即停止更新插槽内容。

有没有办法实现我想要做的事情?

任何帮助将不胜感激。

旁注:我尝试创建一个简单的 Gist 来演示该问题,但我能找到的最新 CDN 版本似乎还不支持视图槽(我无法得到它去工作)。 :(

基本上我想做的是:

list.html

<template>
    <div>list: ${counter}</div>
    <slot></slot>
    <button click.delegate="load()">Increase counter</button>
</template>

list.ts

import { autoinject } from 'aurelia-dependency-injection';
import { customElement } from 'aurelia-templating';

@customElement('list')
@autoinject
export abstract class List {
    public abstract counter;
    public abstract load();
}

resource.html

<template>
    <require from="./list"></require>

    <list>
        <div>resource: ${counter}</div>
    </list>
</template>

resource.ts

import { autoinject } from 'aurelia-dependency-injection';
import { List } from './list';

@autoinject
export class App extends List {
    public counter = 0;

    constructor() {
        super();
    }

    public load() {
        this.counter++;
    }
}

这给出了以下输出:

list: 0
resource: 0
<button>Increase counter</button>

点击按钮后,它应该增加列表和资源计数器,但它仍然显示资源的“0”。 我的猜测是按钮正在调用抽象父类上的加载函数,该类没有实现,因此什么也不做。将按钮更改为子类会起作用,但并不能真正帮助我实现代码减少目标。如何继续使用实施者的(资源)绑定上下文?有办法吗?还是我完全偏离了轨道?

编辑
所以我找到了一种解决方法,但感觉不对。我在List 中更改了以下位:

@bindable({defaultBindingMode: bindingMode.twoWay}) public abstract counter:number;

然后在resource HTML:

<list counter.bind="counter">
    <div>users: ${counter}</div>
</list>

这样,它会同步counter 属性的绑定上下文。我希望有一种方法可以告诉 List 根本没有自己的绑定上下文,因为这在理论上可能会导致很多很多可绑定的。有谁知道我如何告诉List 继承绑定上下文?

编辑 2
为之前的 EDIT 找到了另一种解决方法,删除了可绑定行为并在 List 组件中实现了 bind 回调。这使我可以访问父绑定上下文作为第一个参数。我在List 组件中本地保存,然后在counter 属性更改时手动更新父绑定上下文。这仍然是一种解决方法,因为这会使List 组件很大,但让我不必担心资源中的绑定。 List 现在看起来像这样:

import { customElement } from 'aurelia-templating';
import { autoinject } from 'aurelia-dependency-injection';
import { observable } from 'aurelia-binding';

@customElement('list')
@autoinject
export abstract class List {
    private parentContext;
    @observable public abstract counter:number;

    bind(bindingContext) {
        this.parentContext = bindingContext;
    }

    counterChanged(newValue) {
        if (this.parentContext) this.parentContext.counter = newValue;
    }

    public abstract load();
}

我仍然对完全删除 List 组件的绑定上下文让它继承父绑定上下文的方法感兴趣。

注意在此GitHub issue 中提到的指令.inheritBindingContext 的作用类似于one-time 初始继承,因此在我的情况下没有用,但可能对其他人有用。

【问题讨论】:

  • 检查绑定上下文,我可以看到List中的上下文更新为new content,但是你的resource.html中的上下文仍然绑定到app message
  • @JessedeBruijne 感谢您的评论,这使它更加有趣。更新了父上下文,而使用了更改上下文的子上下文实现..?
  • @JessedeBruijne 更新了问题以突出 Listresource 的绑定上下文之间的差异

标签: typescript aurelia


【解决方案1】:

看看这篇博文 Aurelia Dynamic Compose 使用 compose 和 v-model 和 model,你可以在同一个列表中拥有不同的自定义元素

【讨论】:

  • 感谢您的链接,但我不能将 compose 与可更换部件或视图槽结合使用。我可以制作单独的组成部分,但我真的更喜欢有一个单一的视图和视图模型,就像可以为每个资源扩展的父抽象 List 组件一样。
  • 虽然理论上可以回答这个问题,it would be preferable 在这里包含答案的基本部分,并提供链接以供参考。有关如何编写更好“基于链接”的答案的说明,请参阅here
【解决方案2】:

在编辑 2 之后,当我实现了多个资源列表时,我仍然遇到问题。似乎它正在执行各种功能 x 次。因此,我现在只更新父(资源)上下文,而不是手动同步绑定上下文,如下所示:

列表.ts

import { customElement } from 'aurelia-templating';

@customElement('list')
export abstract class List {
    public parentContext;
    public abstract counter:number;

    bind(bindingContext) {
        this.parentContext = bindingContext;
    }

    public abstract load();
}

列表.html

<template>
    <div>list: ${parentContext.counter}</div>
    <slot></slot>
    <button click.delegate="parentContext.load()">Increase counter</button>
</template>

这不仅降低了我的List 的复杂性,而且更有意义并且更不容易出错。

【讨论】:

  • 这个类是否仍然需要抽象才能工作?
  • @JessedeBruijne 可能不会,但更清楚的是,这个类不能单独使用。这也允许属性和函数也是抽象的,需要资源类来实现它们。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多