自定义元素的绑定上下文 - 它到底是什么,如何访问父 VM

Custom element's Binding Context - what is it exactly, how to access parent VM

我在文档中找不到答案,所以我在这里问。传递给自定义元素的 bind 方法的绑定上下文到底是什么。它是否简单地等于 路由器当前活动的 ViewModel?至少,这就是我到目前为止所发现的。

为什么它不是元素的父级(在 DOM 的术语中)VM?

使用此代码

@customElement("myelem")
@inlineView("<template><content></content></template>")
export class MyElem{
    bind(ctx){
      console.log(ctx);
    }
}

// welcome.html
<myelem>
    <h3>inside myelem</h3>
    <myelem>
      <h4>inside inside ... </h4>
    </myelem>
  </myelem>

控制台中的输出只是当前视图模型 (Welcome) 打印了两次。

我希望第一次(外部)myelemWelcome,但第二次(内部)出现 MyElem...

请解释为什么我在这里错了,内部自定义元素如何知道它的实际上下文(我指的是上述情况下的外部元素),而不使用像创建 secret 属性 在 "shared" 上下文中(实际传递给他们两个的那个)

在数据绑定方面,两个元素都绑定到相同的绑定上下文。考虑这个例子:

<div foo.bind="bar">
  <div foo.bind="bar"></div>
</div>

您会期望两个 <div> 元素具有相同的绑定上下文吗?两个元素的 foo 属性 应该绑定到同一模型的 bar 属性。在这种情况下也是如此:

<myelem foo.bind="bar">
  <myelem foo.bind="bar"></myelem>
</myelem>

<myelem> 的两个实例都绑定到相同的绑定上下文/模型。

如果我对问题的理解正确,您会想要一种优雅的方式来为内部 MyElem class 实例提供对外部 MyElem class 实例的引用。幸运的是,您使用的是 Aurelia,因此有一种非常好的方法可以做到这一点......使用 inject 装饰器将其声明为依赖项:

import {inject, Parent} from 'aurelia-dependency-injection';
import {customElement} from 'aurelia-framework';

@customElement("myelem")
@inject(Parent.of(MyElem))
export class MyElem {
  constructor(parent) {
    this.parent = parent;
  }
  ...
}

但是有一个警告......

Aurelia 依赖项注入容器的默认行为是在容器中找不到实例时创建所请求项目的实例。这意味着 @inject(Parent.of(MyElem)) 不是我们想要的。在没有父 MyElem 实例的情况下,容器将为我们创建一个而不是返回 null。通常我们会使用 @inject(Optional.of(MyElem)) 告诉容器给我们实例,只有当它存在于容器中时。我不知道有什么方法可以组合 Parent.of 和 Optional.of。我将在 aurelia 依赖注入存储库中创建一个问题,以便我们可以添加此功能。

与此同时,我们可以轻松创建自己的 Resolver,它结合了 Parent.of 和 Optional.of 的行为:

import {resolver} from 'aurelia-dependency-injection';

@resolver()
export class OptionalParent {
  constructor(key) {
    this.key = key;
  }

  get(container) {
    if (container.parent && container.parent.hasResolver(this.key, false)) {
      return container.parent.get(this.key)
    }
    return null;
  }

  static of(key) {
    return new OptionalParent(key);
  }
}

所以我们的 MyElem class 的新版本看起来像这样:

import {inject} from 'aurelia-dependency-injection';
import {customElement} from 'aurelia-framework';
import {OptionalParent} from './optional-parent';

@customElement("myelem")
@inject(OptionalParent.of(MyElem))
export class MyElem {
  constructor(parent) {
    this.parent = parent;
  }
  ...
}

这是一个工作示例。检查控制台以获取显示结果的日志消息:

https://gist.run/?id=1a84e0a466fb928aa075