在自定义绑定中扩展可观察项



我有一个自定义绑定处理程序,我将它绑定到视图模型中的一个复杂对象。

绑定处理程序工作正常,并且在可观察对象的任何属性更新时调用update函数。然而,update函数是为每个更新的属性调用的,这导致了奇怪的行为,因为我依赖于整个对象的可用性和最新性。

我理解为什么会发生这种情况,因为每个属性都会导致调用更新,我想我知道如何通过使用Knockout的延迟更新功能来防止这种情况。

然而,我无法找到如何仅为自定义绑定中的可观察对象启用延迟更新。我不想在应用程序范围内启用它,因为我正在将绑定作为库函数编写。

我尝试了许多不同的方法,包括:

  • 试图扩展绑定处理程序本身
  • 扩展了CCD_ 3函数
  • 扩展CCD_ 4
  • 用应用了CCD_ 6的新的可观察物替换CCD_
  • 创建计算出的可观察的并重新绑定所述元素

所有这些都不起作用。

我还没有发现任何其他自定义绑定处理程序与这类函数非常接近,并且一直在尝试将其与其他函数组合在一起。

我的绑定代码本身相对简单,我接受绑定对象,简单地将参数拆分并传递给代码镜像实例。

ko.bindingHandlers.editor = {
init: function(element, valueAccessor, allBindingsAccessor) {
var observableValue = ko.utils.unwrap(valueAccessor());
initEditor(element, observableValue, allBindingsAccessor);
},
update: function(element, valueAccessor, allBindingsAccessor) {
var observableValue = ko.unwrap(valueAccessor());
createEditor(codeEditorDiv, observableValue);
resize();
updateEditor(element, observableValue, allBindingsAccessor);
}
};

我的HTML代码是:

<div id="editor" data-bind="editor: EditorVM"></div>

我在ViewModel中使用了Dotnetify,所以它是一个合理复杂的C#类,但可以说绑定正在工作和更新,但我只需要它在所有属性更新后调用"update"。

很遗憾,您还没有展示initEditorcreateEditorupdateEditorobservableValue的作用,因为这可能是您应该扩展可观察性的地方。

绑定的initupdate方法创建计算的依赖关系,这意味着从init开始在调用堆栈中展开的任何可观察到的内容都将导致调用update方法。

在一个抽象的例子中:

const someVM = ko.observable({
a: ko.observable(1),
b: ko.observable(2),
c: ko.observable(3)
});
// Some function that unwraps properties
const logABC = function(vm) {
console.log(
vm.a(),
vm.b(),
vm.c()
);
}
// Regular binding update:
ko.computed(function update() {
console.log(
"Regular binding update:",
)
logABC(someVM())
});
// Change VM
someVM(someVM());
// Change a, b, and c
someVM().a("A");
someVM().b("B");
someVM().c("C");
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

注意,update被称为:

  1. 初始化计算的
  2. 更改包含视图模型的可观察对象时
  3. 当更改视图模型的任何可观察属性时

有几种方法可以解决这个问题,其中最简单的是在绑定的init方法中创建自己的computed,并将其扩展为deferred

const someVM = ko.observable({
a: ko.observable(1),
b: ko.observable(2),
c: ko.observable(3)
});
const getABC = function(vm) {
return [vm.a(), vm.b(), vm.c()].join(", ");
}
ko.bindingHandlers.renderABC = {
init: function(el, va) {
el.innerText += "Init.n";

// This ensures any inner unwrapping gets deferred
var updateSub = ko.computed(function update() {
el.innerText += getABC(ko.unwrap(va())) + "n";
}).extend({ deferred: true });

ko.utils.domNodeDisposal.addDisposeCallback(el, function() {
updateSub.dispose();
});
}
}
ko.applyBindings({ someVM: someVM });
// Change VM
someVM(someVM());
// Change a, b, and c
someVM().a("A");
someVM().b("B");
someVM().c("C");
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<pre data-bind="renderABC: someVM"></pre>

最新更新