Knockout“with”绑定删除了我的jquery DOM事件

时间:2017-10-31 12:27:51

标签: javascript jquery dom knockout.js

我有几个在DOM加载或文档就绪时创建的jquery dom事件。这些主要是默认行为,应该应用于我的应用程序中的所有表单。例如:

$('input:text').focus(function ()
{
    $(this).select();
});

在应用淘汰赛绑定之前,我可以检查我的dom元素,所有事件都在那里:

before knockout binding

但是当我运行applyBindings方法将viewmodel绑定到我的DOM时,"with" binding会删除与knockout无关的所有事件:

after knockout biding

我已尝试按照documentationthis answer上的说明覆盖 cleanExternalData 。但是这对此没有帮助,函数被替换,但是当在绑定过程中应用模板时,事件仍然从DOM中删除。

对于记录,这不是 with 函数的独占行为,但所有匿名模板函数也会执行此操作,foreach,if,ifnot。正如预期的那样,使用模板也可以采用相同的方式。 DOM元素被完全销毁,存储为模板,然后在条件满足时再次添加到我的文档中,但现在没有任何jquery事件处理程序。

如何避免敲除从DOM元素中删除事件?

2 个答案:

答案 0 :(得分:1)

您可以使用数据绑定来使用jquery on()功能来处理事件,而不是将元素绑定到特定节点。这是我使用的绑定:

define(['knockout'], function (ko) {
ko.bindingHandlers.eventListener = {
    init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        var params = ko.utils.unwrapObservable(valueAccessor());
        if (!(params instanceof Array)) {
            params = [params];
        }
        params.forEach(function (param) {
            $(element).on(param.event, param.selector, function (event) {
                param.callback(ko.dataFor(this), ko.contextFor(this), event);
            });
        });
    }
}

});

用法:

<div data-bind="eventListener: [
             { event: 'click', selector: '.copyInclusionRule', callback: copyInclusionRule},
             { event: 'click', selector: '.deleteInclusionRule', callback: deleteInclusionRule}]">
 ... other knockout template stuff here ...
</div>

以上内容将侦听具有指定类的元素上的单击事件,并在div的“范围”内的任何内容收到事件时执行回调。 'event'param的值可以是on()使用的任何值。

我认为你无法利用cleanNode覆盖的原因是你的dom被完全破坏并重新创建..至少这是我的理论,如果有办法获得某种内存ID pre-applyBindings()dom元素然后在调用applyBindings之后,是那些新节点?如果它们是新节点,那么你无法通过清理解决这些问题,那些节点就不复存在了。

答案 1 :(得分:0)

好的,这就是我如何解决我的问题,我希望这可以向其他不想破坏他们的DOM的人澄清事情。如果您不希望敲除破坏DOM,那么从版本2.2开始就可以实现。因此,在不需要的情况下销毁DOM不是预期的行为,可以避免。

之前我曾尝试过几次由Michael Best创建的出价,例如他的using binding that will come in knockout 3.5,以及let或withLight(现在变为使用)。没有真正有效。这些简化的出价将加载初始对象,但在此对象属性发生更改时不会更新dom。

但这帮助我弄清楚我做错了什么。当我想更新我的可观察对象时,我正在使用 myViewModel.observableObject(NewObject),就像documentation告诉我要做的那样:

  

要向observable写入新值,请调用observable并将新值作为参数传递。例如,调用 myViewModel.personName('Mary')会将名称值更改为“Mary”。

但是我没有传递单个属性的值,我传递的是一个具有相同结构(相同属性)的新对象。这引发了淘汰旧物体被摧毁(因此,虚伪一秒钟)和一个新物体取而代之,即使所有属性都在那里,它们只有不同的值。与文档告诉我的不同,它不仅仅是更改了值,而是更改了整个对象。

要解决这个问题,不要这样做,首先,我必须使用虚拟数据启动我已创建此对象的viewModel,这使得当调用 applyBindings 时,淘汰不会破坏DOM。然后,当我想要更新对象时,我将可观察对象的每个属性的值替换为具有新对象的值。这没有破坏对象和淘汰赛正确更新我的绑定。

myViewModel.setSelectedItem = function setSelectedItem (newObject)
{
    for (var prop in myViewModel.myObservableObject())
        myViewModel.myObservableObject()[prop](newObject[prop]);
}

with 绑定仍然会杀死我的一些事件(例如,我的某个组件的角度ng-change),但它保留了所有jquery事件(这很棒)。并且using绑定根本没有杀死我的任何事件(甚至更好)。