Aurelia 自定义属性,用于更改 HTML 内部元素



用例

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

问题

使用正常绑定时,内部 HTML 不会更改。我认为,一旦HTML用"纯"Javascript更新,Aurelia就会失去绑定。

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

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

  • 情况 1:无属性。文本已更新。这很好。
  • 情况 2:文本未更新。预期:更新文本,但不应加粗(缺少值更改调用(。
  • 情况 3:文本已更新但未加粗(缺少值更改调用(。这很好。
  • 情况 4:文本未更新。扩展:更新文本并使其加粗
  • 情况 5:文本更新并加粗。这很好。

问题

有人可以解释一下,案例 2 和 4 的内部混乱是什么?


法典:

应用.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>

粗体自定义属性.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 的帖子和正确的调试位置来准确了解正在发生的事情。

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

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

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

由于这一点,案例 4 适用于一个输入更改。VM 构造后,绑定正确,更改值有效。内插绑定正在更新文本节点,然后调用valueChanged(),并且具有绑定的文本节点将从 DOM 中消失。


我玩了一会儿,设法改变了绑定。当然,这不应该在生产中使用。添加created()时,一切都"很好"。

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>';
}
}

最新更新