环顾四周后,我看到很多人处理Knockout处理with
绑定方式所引起的问题,特别是在应用with
绑定的元素内删除和替换DOM元素时。我在Prevent "with" binding from removing DOM elements (Knockout.js)看到一个案例,在Knockout.js Using "with" Binding woes看到一个相关问题。我甚至在https://github.com/mbest/knockout/issues/9和https://github.com/knockout/knockout/pull/476跟踪了有关此问题区域的一些讨论。
我了解到从2.2.0开始的版本有所改进,但尽管有这些改进,我仍然看到了一个问题。我在http://jsfiddle.net/bluemonkmn/dSp3L/的JSFiddle中演示了它,其代码在下面复制以供快速参考。
<div data-bind="with: sampleObj">
<button id="bob" data-bind="text:sampleValue"></button>
<button data-bind="click:$root.update" id="update">Update</button>
</div>
var sample = ko.observable({
sampleValue: "Demo"
});
ko.applyBindings({
sampleObj: sample,
update: function () {
sample({
sampleValue: sample().sampleValue + "x"
});
}
});
bob.onclick = function () {
alert("bob");
};
当您点击第一个按钮时,会弹出一个警告。然后单击第二个按钮,它将替换视图模型的值。到现在为止还挺好。但是请注意第一个按钮的事件处理程序已经消失,单击它不再显示消息。
我尝试为“with”绑定创建一个非常便宜的替代品,如下所示:
ko.bindingHandlers.safeWith = {
'init': function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
return { 'controlsDescendantBindings': true };
},
'update': function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var dataValue = ko.utils.unwrapObservable(valueAccessor());
if (dataValue) {
childContext = bindingContext.createChildContext(dataValue);
ko.applyBindingsToDescendants(childContext, element);
}
}
};
这非常适合在with块中保留事件处理程序。但是,我发现每次发生这种情况时,一些事件处理程序会加倍,因为不会被删除。我在http://jsfiddle.net/bluemonkmn/dSp3L/2/
的小提琴的更新版本中证明了这一点当您单击第一个按钮时,您仍然会收到消息,即使您单击第二个按钮以更新该值,它仍会继续工作。但是,如果再次单击第二个按钮,您会发现每次更新值时,事件处理的次数都会增加一倍。
是否有一种简单的方法来修复此“with”实现。我宁愿不使用knockout.js
的分叉副本,因为我希望能够跟上最新版本。理想情况下,我只想要一个像withlight
这样的绑定处理程序,它可以独立而不需要knockout.js
的分支,并且还可以反映更新的视图模型的值而不会丢失事件处理程序。
澄清:在我的真实代码中显示警报的click事件实际上是一个事件处理程序,它被类似(我相信)的代码附加到jQuery-UI中所见的代码,您只需调用它DOM元素上的初始化函数,它调整DOM并设置事件以使ti像一个很好的控件一样工作。我无法控制如何附加此事件,除非确定何时调用此高级函数来设置所有内容。
答案 0 :(得分:0)
避免with
绑定选项吗?
<div>
<button id="bob" data-bind="text: sampleObj().sampleValue"></button>
<button data-bind="click: update" id="update">Update</button>
</div>
<强>更新强>
看起来像if,ifnot和foreach等其他控制流绑定应该在dom 中绑定到可观察的时添加和删除元素。
所以我想知道让你的孩子语境不可观察是否可行?例如,而不是这个,
var sample = ko.observable({
sampleValue: "Demo"
});
...尝试更像这样的东西?
var sample = {
sampleValue: ko.observable('Demo')
};
这样,你的观察者每次都不会被摧毁,我们只会改变这个值。这是小提琴:http://jsfiddle.net/VFKR6/1/
......这就是代码的样子:
<!-- unchanged from the OP -->
<div data-bind="with: sampleObj">
<button id="bob" data-bind="text:sampleValue"></button>
<button data-bind="click:$root.update" id="update">Update</button>
</div>
// don't make sample observable, only make sample.sampleValue observable
var sample = {sampleValue: ko.observable("Demo")};
ko.applyBindings({
sampleObj: sample,
update: function () { sample.sampleValue(sample.sampleValue() + 'x'); }
});
bob.onclick = function() {alert("bob");};
这样做你想要的,改变子上下文中按钮的文本,它不会破坏bob.onclick事件。