"if" 和 "with" 绑定处理程序导致所有事件处理程序丢失(即使使用 jQuery 的 on() 创建)

"if" and "with" binding handlers causing all event handlers to be lost (even if created with jQuery's on())

我正在使用 KnockoutJS,我注意到一个绑定问题,我可以用这个例子来解释:

<label><input type="checkbox" data-bind="checked: displayMessage" /> Display message</label>
<div data-bind="if: displayMessage">Here is a message.<span id="super">SUPER</span> Astonishing.</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.3.0/knockout-min.js"></script>
$(function(){
    ko.applyBindings({
        displayMessage: ko.observable(true)
    });

    $('#super').on("click", function(){
        alert('SUUUUUPER');
    });
});

当您第一次单击 "SUPER" span 元素时,会出现警报。但是,如果您通过将模型的 属性 displayMessage 设置为 false 并将其放回 true 以再次显示它来删除块,则绑定到点击事件是不再工作。

ififnotwith bindingHandlers的源代码我知道knockout删除了DOM clone并保存它第一次并重新追加它使用虚拟元素 API.

所以我的问题是:知道 jQuery on() 实用程序将事件处理程序附加到所选元素,即使它们尚不存在。是使用导致点击绑定丢失的虚拟元素。如果不是:向我解释会发生什么。

我不会在带有 KO 控制标记的元素上使用 id。问题是:Knockout 将克隆元素、重组 DOM 等,您最终可能会得到多个具有相同 id 的元素,这是无效的,从那时起基于 ID 的浏览器行为是不可预测的.

此外,因为 if 绑定 KO 会 remove/add DOM 节点在运行中,你需要 this advice 来确保 jQuery on 函数也处理新创建的元素。

这是一个使用 class 而不是 id 的不同版本,它按预期工作:

$(function(){
    ko.applyBindings({
        displayMessage: ko.observable(true)
    });

    $(document.body).on("click", ".super", function(){
        alert('SUUUUUPER');
    });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.3.0/knockout-min.js"></script>

<label><input type="checkbox" data-bind="checked: displayMessage" /> Display message</label>
<div data-bind="if: displayMessage">Here is a message.<span class="super">SUPER</span> Astonishing.</div>

注意:

  • 您也可以使用 visible 绑定,这 可能 避免需要提到的 on-建议。
  • 您应该尽量避免使用 jQuery 进行此类事件处理,而应改用 Knockout 的 MVVM 式事件处理(利用 click 绑定)。