关于jQuery:将全局ajax事件绑定到非DOM对象上

3

基本模块问题在这里:如果我放弃使用模块模式,我可以很好地让全局处理程序正常工作,但是这个测试代码不起作用,我很难找出原因。

var MyModule = (function($, my) {
  $(my).ajaxStart(function() { window.alert("ajax start"); });

  $(document).ready(function() {
    $.ajax(SOME_AJAX_SETTINGS_HERE);
  });

  return my;
}(jQuery, MyModule || {}));

当ajax调用执行时,附加到MyModule实例的处理程序从未运行。如果我改为将处理程序附加到$(document),那么它就可以正常工作,但是我很好奇为什么全局事件似乎无法正确地绑定到模块对象。

编辑:这里有一个更简单的示例:

var x = {};
$(x).ajaxStart(function() { window.alert("foo"); } );
$.ajax(SOME_AJAX_SETTINGS);

如果我用$(document)来代替$(x),它就能正常工作了...这似乎只是因为我不能将ajaxStart(或其他全局ajax事件)绑定到非DOM对象上?
@Nucleon,我认为这并不完全正确,下面是一个例子:
var item = {foo: function() { window.alert("shorthand"); } };
$(item).bind("foo", function () { window.alert("longhand"); } );
window.alert("about to trigger (locally)");
$(item).trigger("foo");
window.alert("now we triggerHandler (locally)");
$(item).triggerHandler("foo");

这里,自定义事件“foo”通过两个模式进行绑定,不同的触发方法显示出模式的特异性...您将会收到两次“longhand”警报和一次“shorthand”警报。

现在,您也可以使用$.event.trigger("foo")来触发全局事件(但是,没有相应的全局triggerHandler存在)。 问题是如果您添加以下代码:

window.alert("now we trigger (globally)");
$.event.trigger("foo");

对于此全局事件触发,两个处理程序都不会运行。

然而,如果您将item替换为某个DOM类型的元素--正如您上面所建议的--那么本地和全局事件都会被处理,但缩写处理程序现在将无法工作*。因此,似乎虽然本地处理适用于非DOM对象,但是特别是全局处理不起作用。

-m

*缩写处理程序停止工作,因为缩写模式仅适用于非DOM对象。我个人认为,这种非DOM对象的“缩写”行为应该从jQuery中删除。很少有人知道它,而且它只在全局jQuery对象页面上的一个晦涩的句子中记录...它的行为可能会让不知情的人感到疯狂,因为它隐含地执行了一个绑定步骤,这是人们可能不知道的。


啊,好的...$.event.trigger功能不是公开的,尽管它被底层的事件触发机制使用。我想我只是不应该使用它。 事实证明,这种行为对于jQuery开发人员来说是具有挑战性的,而且看起来他们正在完全放弃它(或者这就是我从这个被标记为“已修复”的错误报告中获得的信息:DEPRECATE AJAX "GLOBAL" EVENT BEHAVIOR)。

但是,我仍然有些困惑于.trigger被记录为对DOM或非DOM对象具有相同的行为方式,因为只有以下一种警报会运行:

var plain = {foo: function() { window.alert("plain"); } };
var dom = $("<div></div>");
dom.foo = function() { window.alert("dom"); };
console.log(plain.foo); // make sure we see function foo on the plain object.
console.log(dom.foo); // now make sure we see function foo on the DOM object.
$(plain).trigger("foo"); // raises the "plain" window alert.
$(dom).trigger("foo"); // raises no alert.

我猜这意味着在控制台检查对象时,设置在dom上的foo属性实际上并不是传统意义上的“正确”JS属性(尽管它显示正确)? 注意:现在这都是为了知识而言——因为我将遵循上面bug链接中的“修复”建议,并将所有我的AJAX(和其他全局)事件绑定到document上,因为它似乎是jQuery 1.9中强制执行的行为。但我已经服用了蓝色药丸,感觉自己已经深入兔子洞而无法爬出来。

我认为你误解了jQuery中事件的工作方式。这不是关于全局本地事件的问题。从jQuery文档中关于$.trigger()的说明:对于普通对象和DOM对象,如果触发的事件名称与对象上的属性名称匹配,jQuery将尝试将该属性作为方法调用,如果没有事件处理程序调用event.preventDefault()。如果不希望出现这种行为,请改用.triggerHandler()。此外,我不知道$.event.trigger("foo")甚至是做什么的,我在文档中找不到这样的调用。 - Owen Allen
1个回答

2

只需将

var x = {};

替换为

var x = $("<div></div>");

Javascript事件需要绑定到有效的DOM对象(而不仅仅是javascript对象)。现在,DOM对象实际上并不需要被附加到任何地方。Javascript的事件系统基于向上和向下沿着可用和相关的DOM对象的层次结构链传播事件。一个简单的{}是不合格的。


有趣的方法...下次需要检查一下。 - Jan.J

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接