Knockout 的 "with" 绑定会丢失包含的绑定上的事件



环顾四周后,我看到了许多人在敲除手柄 with绑定方面引起的问题,这特别涉及删除和更换应用with绑定的元素中的DOM元素。我看到一个案件在"预防"中。从删除DOM元素(quotout.js)和敲除js上的相关问题的绑定。结合困境。我什至在https://github.com/mbest/knockout/issues/9和https://github.com/knockout/knockout/knockout/phockout/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");
};

单击第一个按钮时,警报会弹出。然后单击第二个按钮,该按钮替换了视图模型的值。到目前为止,一切都很好。但是请注意,第一个按钮的事件处理程序已消失,单击它不再显示消息。

我尝试过为"用"绑定的"使用"非常便宜的替代品,如下所示:

  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);
        }
     }
  };

这非常适合保留事件处理程序的块中的元素。但是,然后我发现每次发生这种情况时,某些事件处理程序都会增加一倍,因为他们没有删除。我已经在http://jsfiddle.net/bluemonkmn/dsp3l/2/

的更新版本中演示了这一点。

单击第一个按钮时,您仍然会收到该消息,即使您单击第二个按钮以更新该值后,它仍会继续工作。但是,如果您再次单击第二个按钮,您会注意到每次更新值时,该事件正在处理的次数都会加倍。

是否有一种简单的方法可以通过实现来解决此问题。我宁愿不喜欢knockout.js的分叉副本,因为我希望能够跟上最新版本。理想情况下,我只想要一个像withlight这样的绑定处理程序,它可以独立地站立而无需叉子knockout.js,它也会反映更新的视图模型的价值而不会丢失事件处理程序。

澄清:在我的真实代码中显示警报的点击事件实际上是一个事件处理程序,与jQuery-ui相似的代码(我相信)附加了一个事件处理程序,您只需调用一个DOM元素上的初始化功能,并调整DOM并设置事件以使Ti像一个不错的控件一样工作。我无法控制该事件的附加方式,除了确定何时称此高级功能设置所有内容。

避免with绑定选项?

<div>
    <button id="bob" data-bind="text: sampleObj().sampleValue"></button>
    <button data-bind="click: update" id="update">Update</button>
</div>

update

它看起来与其他控制流绑定(如if,ifnot和foreach)一样,当它们绑定到可观察到的。>

所以我想知道尝试使您的孩子上下文不可观察是可行的吗?例如,而不是这个,

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事件。

最新更新