【发布时间】:2014-02-06 16:52:07
【问题描述】:
环顾四周后,我看到许多人处理由 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 的分支,而且它还将反映更新后的视图模型的价值,而不会丢失事件处理程序。
澄清:在我的真实代码中显示警报的点击事件实际上是一个事件处理程序,它由类似于(我相信)在 jQuery-UI 中看到的代码附加,您只需调用DOM 元素上的初始化函数,它调整 DOM 并设置事件以使 ti 像一个漂亮的控件一样工作。我无法控制此事件的附加方式,除非确定何时调用此高级函数来设置所有内容。
【问题讨论】:
-
如果不是 jqueryui,小部件是什么?是剑道吗?什么控制?如果您可以向元素添加绑定,我仍然不清楚您无法控制什么。您可以运行一个工具函数来重新附加点击期间的行为(如果是剑道,我知道它有事件处理程序)。
-
@danludwig 我们有一套基于 jQuery-UI 并与之并行开发的公司控件。我也许能够更新这些控件,但仅仅为了使某些用例具有淘汰赛工作,这不是一个黑客行为。在我看来,更好的“with”实现将是一个更清洁的解决方案。毕竟,“with”本质上是在不必要地删除事件。我想要做的就是引用一个特定的范围,而不必在每个数据绑定属性中包含父变量名。我不希望 DOM 到处移动。
-
这不完全是这个问题的答案,但与我们的情况非常相关——请参阅stackoverflow.com/q/21415232/78162
标签: knockout.js