我有一个自定义绑定(bind)处理程序,我要绑定(bind)到我的 View 模型中的一个复杂对象。
绑定(bind)处理程序正常工作,并且当任何可观察对象的属性更新时调用 update
函数。但是,update
函数会为每个 更新的属性调用,这会导致奇怪的行为,因为我依赖于整个对象的可用性和最新状态。
我理解为什么会发生这种情况,因为每个属性都会导致调用更新,而且我想我知道如何防止这种情况 - 通过使用 deferred updates Knockout 的功能。
但是,我无法找到如何仅针对自定义绑定(bind)中的可观察对象启用延迟更新。我不想在应用程序范围内启用它,因为我将绑定(bind)编写为库函数。
我尝试过很多不同的方法,包括:
- 尝试扩展绑定(bind)处理程序本身;
- 扩展
init
函数; - 扩展
valueAccessor
; - replacing the
valueAccessor
with a new observable withdeferred
applied ; - creating a computed observable and rebinding the element ;
所有这些都没有用。
我还没有发现任何其他的自定义绑定(bind)处理程序与此类功能相差甚远,并且一直在尝试将其与其他功能拼凑在一起。
我的绑定(bind)代码本身相对简单,我获取绑定(bind)对象并简单地拆分参数并将它们传递给代码镜像实例。
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>
我正在使用 Dotnetify对于 ViewModel,它是一个合理的复杂 C# 类,但足以说明绑定(bind)正在工作和更新,但我需要它仅在所有属性都已更新后才调用“更新”。
最佳答案
很遗憾你没有展示什么initEditor
, createEditor
和 updateEditor
用 observableValue
做,因为这可能是您应该扩展可观察对象的地方。
init
和 update
绑定(bind)的方法创建计算依赖项,这意味着 任何 在调用堆栈中从 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
被称为:
- 初始化计算时
- 更改包含 View 模型的可观察对象时
- 更改 View 模型的任何可观察属性时
有多种方法可以解决此问题,其中最简单的是创建您自己的 computed
在init
里面您的绑定(bind)方法并将其扩展为 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>
关于javascript - 在自定义绑定(bind)中扩展可观察对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53147766/