Aurelia 更改元素内部的自定义属性 HTML

Aurelia Custom attribute which changes the elements inner HTML

用例

我有一个自定义属性,它可以更改附加元素的内容,例如从非粗体到粗体。

问题

使用正常绑定,内部 HTML 不会改变。我认为,一旦 HTML 更新为 "plain" Javascript.

,Aurelia 就会失去绑定

您可以在这个 GistRun 中看到它:https://gist.run/?id=6f16ac1c8affb0277d7ad5c53d433482

更改区域中的文本。有五种情况:

问题

谁能给我解释一下,案例 2 和案例 4 内部发生了什么?


代码:

app.html

<template>
  <require from="./bold-custom-attribute"></require>

  <textarea value.bind="content"></textarea>
  <pre>${content}</pre>
  <pre bold>${content}</pre>
  <pre bold textcontent.bind="content"></pre>
  <pre bold.bind="content">${content}</pre>
  <pre bold.bind="content" textcontent.bind="content"></pre>
</template>

大胆定制-attribute.js

export class BoldCustomAttribute {
  static inject = [Element];

  constructor(element) {
    this.element = element;
  }

  bind() {
    //this.bolden(this.element);
  }

  attached() {
    this.bolden(this.element);
  }

  valueChanged(newValue, oldValue){
    this.bolden(this.element);
  }

  bolden(anElement) {
    anElement.innerHTML = '<b>' + anElement.innerText + '</b>';
  }
}

按照您现在的方式修改 HTML,会导致创建新的 DOM 元素,因此 Aurelia 不再引用它需要的 DOM 元素更新绑定值。

通过结合 Ashley、Fabio 的 post 和正确的调试位置,我能够准确地找出发生了什么。

${content} 字符串插值都得到一个 ChildInterpolationBinding 绑定到它们形成的文本节点(在 <pre> 中,尽管在 Chrome 中不直接可见调试器),或更准确地说 textContent 属性。 这意味着,一旦 <pre> 的内部 HTML 被 bolden() 替换,文本节点就会从 DOM 中消失(但是,绑定仍然存在并且正在更新文本节点 textContent)。新节点当然没有绑定(解释为什么案例 4 不工作)。

现在,情况 5 (textcontent.bind) 的区别在于 Binding 直接附加到指定的 <pre>,或更准确地说是 [=21] =] 属性。如果 <pre> 中的内容发生变化(例如通过 textContentinnerHTML),绑定仍在正确的节点上 (<pre>)。

编辑 Ashley 在这里提到的一个重点是 textcontent 绑定在 valueChanged() 之前调用。这使得案例 5 完全可行。首先,更新 textcontent(使用不会丢失的绑定),然后触发读取刚刚更新的文本内容并应用新的 HTML 标签的值更改。

由于这一点,案例 4 适用于一个输入更改。 VM构建完成后,绑定正确,更改值工作。插值绑定正在更新文本节点,然后调用 valueChanged() 并且带有绑定的文本节点从 DOM.

中消失

我玩了一会儿,设法改变了绑定。 当然,这不应该用于生产。 添加 created() 时,一切正常 "fine"。

export class BoldCustomAttribute {
  static inject = [Element];

  constructor(element) {
    this.element = element;
  }

  created(owningView, myView) {
    if (this.element.hasChildNodes() && this.element.firstChild.auInterpolationTarget === true) {
      owningView.bindings.forEach(binding => {
        if (binding.target === this.element.firstChild) {;
          binding.target = this.element;
          binding.targetProperty = 'innerHTML';
        }
      });
    }
  }

  bind() {
    this.bolden(this.element);
  }

  valueChanged(newValue, oldValue){
    this.bolden(this.element);
  }

  bolden(anElement) {
    anElement.innerHTML = '<b>' + anElement.innerText + '</b>';
  }
}