用例
我有一个自定义属性,可以更改它附加的元素的内容,例如从非粗体到粗体。
问题
使用正常绑定时,内部 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>
中的内容发生变化(例如通过textContent
或innerHTML
(,绑定仍然在正确的节点上(<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>';
}
}