【发布时间】:2013-08-16 20:54:35
【问题描述】:
好吧,我已经尝试解开这个烂摊子几个小时了,但无济于事,类似于狗追逐它的尾巴。情况是这样的。
我在我的 UI 中使用了 Knockout.js,它本身就很好用。但是,我正在尝试使用一些第三方代码,使下拉菜单和复选框看起来都很漂亮。实际上,我什至不确定这是第三方库还是我们的设计师写的东西。此代码隐藏真正的复选框,并将其替换为通过 CSS 模仿复选框的假 <span />。 span的click事件触发真实checkbox的change事件:
// this code updates the fake UI
this._changeEvent = function() {
self.isChecked = self.$input.is(':checked');
self._updateHTML(false, true);
jQuery(self).trigger('change');
};
// when the user clicks the fake checkbox, we trigger change on the real checkbox
this.$fake.on('click', function(e) {
e.preventDefault();
self.$input.click().trigger('change');
});
// Bind _changeEvent to the real checkbox
this.$input.change(this._changeEvent);
这实际上适用于 Knockout.js,因为 Knockout 将侦听该事件处理程序。换句话说,当用户点击虚假复选框时,绑定的 Knockout 模型会更新。但是,不起作用的是更新模型。如果我打电话:
model.SomeValue(!curValue); // SomeValue is bound to a checkbox, flip its value
模型已更新,但假 UI 未更新。我已经将此问题追溯到ko.bindingHandlers.checked.update 中的代码,该代码执行以下操作:
// When bound to anything other value (not an array), the checkbox being checked represents the value being trueish
element.checked = value;
基本上,element.checked 属性已设置,但不会触发任何事件。因此,永远不会调用 _changeEvent 函数。所以,我实现了自己的ko.bindingHandlers.checked.update 函数,它是内置函数的副本。理论上,这就是我需要做的所有事情:
ko.bindingHandlers.checked.update = function (element, valueAccessor)
{
var value = ko.utils.unwrapObservable(valueAccessor());
if (element.type == "checkbox")
{
if (value instanceof Array)
{
// When bound to an array, the checkbox being checked represents its value being present in that array
element.checked = ko.utils.arrayIndexOf(value, element.value) >= 0;
}
else
{
// When bound to anything other value (not an array), the checkbox being checked represents the value being trueish
//element.checked = value;
$(element).prop('checked', value).trigger('change'); // <--- this should work!
}
}
else if (element.type == "radio")
{
element.checked = (element.value == value);
}
};
我没有设置element.checked,而是调用.prop('checked', value) 并触发更改事件。但是,这是行不通的。以下是我目前所知道的:
- 如果我从等式中删除 Knockout.js,
$(element).prop('checked', value).trigger('change');工作得非常好。所以,knockout.js 以某种方式搞砸了这个事件。是否取消绑定该事件处理程序? - 我已经确认
$(element)与假复选框绑定代码中的this.$input相同。我可以在这个元素上设置其他 expando 属性,它们就会显示出来。 - 我已经尝试了一些方法来尝试调试 Knockout.js 和 jQuery 以查看事件是否仍然被绑定,但是我并没有真正使用这种方法。我的预感是,Knockout.js 以某种方式将
change事件处理程序替换为它自己的内部事件处理程序,并且现有的绑定被删除了。我还没有找到方法来确认这一点。
我的问题:主要是,我正在寻找解决此问题的方法。 Knockout.js 是否会删除应用模型之前存在的现有 change 事件?调试此代码并弄清楚到底发生了什么的下一步是什么?
【问题讨论】:
-
+1 多么粗鲁,确实:)
-
+1 写得很好的问题。 (还没有)对此进行深入研究,但是浏览 KO 源代码,我确实看到utils.js 中的
RegisterEventHandler在涉及 jQuery 时对复选框的特殊处理有相当长的评论。也许这是一个线索? -
@Esailija - 是的,我想我必须构建一个完全独立的可重现示例。叹息。
-
在 jQuery 中使用 Knockout 时,包含顺序很重要。只有在包含 Knockout 时它存在时,Knockout 才使用 jQuery。
-
@Jeroen - 你可能是对的,正如评论的最后一行所说:“// 通过接收处理程序并在它运行之前应用正确的检查来解决这个问题。”
标签: javascript jquery knockout.js