[javascript] Knockout.js似乎是在破坏我的jQuery事件处理程序,多么粗鲁



2 Answers

尝试触发和收听自定义事件:

element.checked = value;
element.dispatchEvent(new Event("forcedChange"));
Question

好吧,我一直试图解开这个烂摊子几个小时而且已经无处可去,类似于追逐尾巴的狗。 这是情况。

我正在使用Knockout.js作为我的UI,它本身很好用。 但是,我正在尝试使用一些第三方代码,使下拉列表和复选框看起来很漂亮。 实际上我甚至不确定这是第三方库还是我们设计师写的东西。 此代码隐藏了真实的复选框,并将其替换为假的<span /> ,它通过CSS模仿复选框。 span的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将监听该事件处理程序。 换句话说,当用户单击假复选框时,绑定的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)并触发change事件。 但是,这不起作用。 这是我目前所知道的:

  1. 如果我从等式中删除Knockout.js, $(element).prop('checked', value).trigger('change'); 工作得非常好。 所以,knockout.js正在搞这个事件。 它解除了那个事件处理程序吗?
  2. 我已经确认$(element)与此相同this.$input在假复选框绑定代码中this.$input 。 我可以在这个元素上设置其他expando属性,然后它们就会显示出来。
  3. 我尝试了一些方法来尝试调试Knockout.js和jQuery以查看事件是否仍然受限,但是我还没有真正得到这种方法。 我的预感是,Knockout.js以某种方式用自己的内部处理程序替换了change事件处理程序,并删除了现有的绑定。 我还没有办法确认这一点。

我的问题:主要是,我正在寻找解决这个问题的方法。 Knockout.js是否删除了在应用模型之前存在的现有change事件? 调试此代码并确切了解发生了什么的下一步是什么?




听起来你所遇到的问题不是由于来自淘汰赛和另一组代码的事件中的冲突(例如,更改复选框的CSS),而是由于Javascript线程和事件中的事件发生冲突线程,被处理。

Javascript在浏览器中作为单个线程处理:所有进程按顺序运行,任何中断序列的事件都可能导致事件失败。 如果您可以单独调用每个函数,但是当您在脚本中包含这两个函数时存在干扰,那么触发复选框的CSS更改的onclick或onmousedown事件可能会干扰knockout脚本。 在这个“单线程”中,所有事件都可以影响另一个事件的执行,甚至鼠标移动。

这个( http://ejohn.org/blog/how-javascript-timers-work/ )示例使用计时器演示了这个想法,但我认为您当前的情况可能会遇到同样的问题。

要解决它,您可以编写一个简短的函数,例如:

function doBoth(checkboxid){

$( “#checkboxid”)addclass( “prettychecked”)。

$(“#checkboxid”)。prop('checked',true);

}

重要的一点是,每个动作都是按顺序进行的,没有鼠标事件中断的可能性。

希望这可以帮助!




只是头脑风暴,但这是使用事件名称空间开发的第三方控件吗? 这可能就像你建议的那样,淘汰赛和这种控制正以某种方式争夺默认的“变化”事件。 当我开发小部件和应用程序时,我总是在使用jQuery绑定事件时使用事件命名空间。

使用'myWidget'命名空间的示例:

$('#element').on('change.myWidget', function(e) {
  // handle the event
}

我可以完全离开基地。




Related