好吧,几个小时以来,我一直在努力解决这个问题,但一无所获,就像一只追逐自己尾部的狗。情况是这样的。
我在我的 UI 中使用 Knockout.js,它本身运行良好。但是,我正在尝试使用一些第三方代码来使下拉菜单和复选框看起来很漂亮。实际上我什至不确定这是第三方库还是我们的设计师写的东西。此代码隐藏真正的复选框并将其替换为假 <span />
通过 CSS 模拟复选框。 click
跨度事件触发 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 将监听该事件处理程序。换句话说,当用户单击假复选框时,绑定(bind)的 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 以某种方式搞砸了这个事件。是否取消绑定(bind)该事件处理程序? - 我已经确认
$(element)
与this.$input
相同在假的复选框绑定(bind)代码中。我可以在此元素上设置其他 expando 属性,它们会显示出来。 - 我已经尝试了几种方法来尝试调试 Knockout.js 和 jQuery 以查看事件是否仍然绑定(bind),但是我并没有真正使用这种方法取得任何进展。我的预感是 Knockout.js 以某种方式取代了
change
具有自己的内部事件处理程序,并且删除了现有的绑定(bind)。我还没有找到确认这一点的方法。
我的问题:主要是,我正在寻找这个问题的解决方案。 Knockout.js 是否删除现有的 change
应用模型之前存在的事件?调试此代码并弄清楚到底发生了什么的后续步骤是什么?
最佳答案
与其覆盖基本的已检查处理程序,不如创建您自己的自定义绑定(bind)来更新 UI。
这是一个模型示例和一个自定义绑定(bind)来处理更新 UI:
var Model = function () {
this.checked = ko.observable(false);
};
ko.bindingHandlers.customCheckbox = {
init: function (element) {
// Create the custom checkbox here
$(element).customInput();
},
update: function (element) {
// Update the checkbox UI after the value in the model changes
$(element).trigger('updateState');
}
};
我会将模型绑定(bind)到以下 HTML:
<input type="checkbox" name="genre" id="check-1" value="action" data-bind="checked: checked, customCheckbox: checked" />
这就是我需要做的全部。
这是一个例子:http://jsfiddle.net/badsyntax/4Cy3y/
[edit] - 我想我匆忙阅读了您的问题,但没有理解您所问问题的症结所在。无论如何,我都会在这里留下我的答案。
关于javascript - Knockout.js 似乎在破坏我的 jQuery 事件处理程序,多么粗鲁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18239621/