令人讨厌的是,jQuery 事件处理程序总是按照它们绑定(bind)的顺序执行。例如:
$('span').click(doStuff1);
$('span').click(doStuff2);
点击 span 将触发 doStuff1()
,然后触发 doStuff2()
。
在我绑定(bind) doStuff2() 时,我希望选择在 doStuff1() 之前绑定(bind)它,但似乎没有任何简单的方法做这个。
我想大多数人会说,就这样写代码吧
$('span').click(function (){
doStuff2();
doStuff1();
});
但这只是一个简单的例子——在实践中这样做并不总是很方便。
有些情况下你想绑定(bind)一个事件,而你绑定(bind)的对象已经有事件了。在这种情况下,您可能只是希望在任何其他现有事件之前触发新事件。
那么在 jQuery 中实现这一点的最佳方法是什么?
更新的答案
jQuery 在 1.8 中更改了事件存储的位置。现在你知道为什么乱用内部 API 是个坏主意了 :)
用于访问 DOM 对象事件的新内部 API 可通过全局 jQuery 对象使用,而不是绑定(bind)到每个实例,它需要一个 DOM 元素作为第一个参数,一个键(对我们来说是“事件”)作为第二个参数。
jQuery._data(<DOM element>, "events");
这里是 jQuery 1.8 的修改代码。
// [name] is the name of the event "click", "mouseover", ..
// same as you'd pass it to bind()
// [fn] is the handler function
$.fn.bindFirst = function(name, fn) {
// bind as you normally would
// don't want to miss out on any jQuery magic
this.on(name, fn);
// Thanks to a comment by @Martin, adding support for
// namespaced events too.
this.each(function() {
var handlers = $._data(this, 'events')[name.split('.')[0]];
// take out the handler we just inserted from the end
var handler = handlers.pop();
// move it at the beginning
handlers.splice(0, 0, handler);
});
};
这是一个 playground .
原始答案
正如@Sean 发现的那样,jQuery 通过元素的data
接口(interface)公开所有事件处理程序。特别是 element.data('events')
。使用它,您始终可以编写一个简单的插件,从而可以在特定位置插入任何事件处理程序。
这是一个简单的插件,可以在列表的开头插入一个处理程序。您可以轻松地扩展它以在任何给定位置插入一个项目。这只是数组操作。但由于我还没有看到 jQuery 的源代码并且不想错过任何 jQuery 魔术,我通常先使用 bind
添加处理程序,然后重新排列数组。
// [name] is the name of the event "click", "mouseover", ..
// same as you'd pass it to bind()
// [fn] is the handler function
$.fn.bindFirst = function(name, fn) {
// bind as you normally would
// don't want to miss out on any jQuery magic
this.bind(name, fn);
// Thanks to a comment by @Martin, adding support for
// namespaced events too.
var handlers = this.data('events')[name.split('.')[0]];
// take out the handler we just inserted from the end
var handler = handlers.pop();
// move it at the beginning
handlers.splice(0, 0, handler);
};
因此,例如,对于此标记,它将作为 ( example here) 工作:
<div id="me">..</div>
$("#me").click(function() { alert("1"); });
$("#me").click(function() { alert("2"); });
$("#me").bindFirst('click', function() { alert("3"); });
$("#me").click(); // alerts - 3, then 1, then 2
但是,据我所知,由于 .data('events')
不是他们公共(public) API 的一部分,因此更新例如,如果附加事件的底层表示从数组更改为其他内容,jQuery 可能会破坏您的代码。
免责声明:因为一切皆有可能 :),这是您的解决方案,但我仍然会在重构现有代码方面犯错,因为只是试图记住这些项目的附加顺序很快就会消失随着您不断添加越来越多的这些有序事件。