Как заказать события, связанные с jQuery
Предположим, у меня есть веб-приложение, в котором есть страница, которая может содержать 4 script блока - script Я пишу, может быть найден в одном из этих блоков, но я не знаю, какой из них обрабатывается контроллер.
Я привязываю несколько событий onclick
к кнопке, но обнаруживаю, что они иногда исполняются в том порядке, который я не ожидал.
Есть ли способ обеспечить порядок или как вы справлялись с этой проблемой в прошлом?
Ответы
Ответ 1
Я пытался на протяжении веков обобщать этот процесс, но в моем случае меня беспокоил только порядок прослушивания первого события в цепочке.
Если это применимо, вот мой плагин jQuery, который связывает прослушиватель событий, который всегда запускается перед любыми другими:
** ОБНОВЛЕНО inline с изменениями jQuery (спасибо Toskan) **
(function($) {
$.fn.bindFirst = function(/*String*/ eventType, /*[Object])*/ eventData, /*Function*/ handler) {
var indexOfDot = eventType.indexOf(".");
var eventNameSpace = indexOfDot > 0 ? eventType.substring(indexOfDot) : "";
eventType = indexOfDot > 0 ? eventType.substring(0, indexOfDot) : eventType;
handler = handler == undefined ? eventData : handler;
eventData = typeof eventData == "function" ? {} : eventData;
return this.each(function() {
var $this = $(this);
var currentAttrListener = this["on" + eventType];
if (currentAttrListener) {
$this.bind(eventType, function(e) {
return currentAttrListener(e.originalEvent);
});
this["on" + eventType] = null;
}
$this.bind(eventType + eventNameSpace, eventData, handler);
var allEvents = $this.data("events") || $._data($this[0], "events");
var typeEvents = allEvents[eventType];
var newEvent = typeEvents.pop();
typeEvents.unshift(newEvent);
});
};
})(jQuery);
Примечания:
- Это не было полностью протестировано.
- Он опирается на внутренности рамки jQuery, которые не изменяются (проверяется только с помощью 1.5.2).
- Он не обязательно будет запускаться перед прослушивателями событий, которые связаны каким-либо образом, кроме как как атрибут исходного элемента, или с помощью jQuery bind() и других связанных функций.
Ответ 2
Если порядок важен, вы можете создавать свои собственные события и связывать обратные вызовы, чтобы они срабатывали, когда эти события вызываются другими обратными вызовами.
$('#mydiv').click(function(e) {
// maniplate #mydiv ...
$('#mydiv').trigger('mydiv-manipulated');
});
$('#mydiv').bind('mydiv-manipulated', function(e) {
// do more stuff now that #mydiv has been manipulated
return;
});
Что-то вроде этого как минимум.
Ответ 3
Метод Dowski хорош, если все ваши обратные вызовы всегда будут присутствовать, и вы довольны тем, что они зависят друг от друга.
Если вы хотите, чтобы обратные вызовы были независимыми друг от друга, вы могли бы воспользоваться преимуществами пузырьков и присоединить последующие события в качестве делегатов к родительским элементам. Обработчики на родительских элементах будут запускаться после обработчиков на элементе, продолжая вплоть до документа. Это неплохо, так как вы можете использовать event.stopPropagation()
, event.preventDefault()
и т.д., Чтобы пропускать обработчики и отменять или отменять действие.
$( '#mybutton' ).click( function(e) {
// Do stuff first
} );
$( '#mybutton' ).click( function(e) {
// Do other stuff first
} );
$( document ).delegate( '#mybutton', 'click', function(e) {
// Do stuff last
} );
Или, если вам это не нравится, вы можете использовать плагин Nick Leaches bindLast, чтобы связать последнее событие: https://github.com/nickyleach/jQuery.bindLast.
Или, если вы используете jQuery 1.5, вы также можете сделать что-то умное с новым объектом Deferred.
Ответ 4
Порядок вызова связанных обратных вызовов управляется каждым событием события объекта jQuery. Нет никаких функций (которые я знаю), которые позволяют вам напрямую просматривать и манипулировать этими данными, вы можете использовать bind() и unbind() (или любую из эквивалентных вспомогательных функций).
Метод Dowski лучше всего, вы должны изменить различные связанные обратные вызовы для привязки к упорядоченной последовательности пользовательских событий, причем "первый" обратный вызов привязан к "реальному" событию. Таким образом, независимо от того, в каком порядке они связаны, последовательность будет выполняться правильным образом.
Единственная альтернатива, которую я вижу, - это то, что вы действительно, на самом деле не хотите созерцать: если вы знаете, что синтаксис привязки функций может быть связан перед вами, попытайтесь удалить все эти функции, а затем повторно Соберите их в правильном порядке. Это просто вызывает неприятности, потому что теперь у вас есть дублированный код.
Было бы здорово, если бы jQuery позволил вам просто изменить порядок связанных событий в данных объектных событий, но без написания кода, чтобы подключиться к ядру jQuery, что не представляется возможным. И есть, вероятно, последствия разрешения этого, о котором я не думал, поэтому, возможно, это намеренное упущение.
Ответ 5
Обратите внимание, что в юниверсе jQuery это должно быть реализовано по-разному с версии 1.8. Следующая заметка о выпуске из блога jQuery:
.data( "events" ): jQuery хранит связанные с событием данные в объекте данных (ожидание) событий для каждого элемента. Это внутренние данные структуры, поэтому в 1.8 это будет удалено из пространства имен данных пользователя поэтому он не будет конфликтовать с предметами с тем же именем. Данные события jQuerys по-прежнему можно получить доступ через jQuery._data (элемент, "события" )
У нас есть полный контроль над порядком, в котором обработчики будут выполняться в юниверсе jQuery. Рику указывает на это выше. Не похоже, что его ответ принес ему много любви, но эта техника очень удобна. Рассмотрим, например, в любое время, когда вам нужно выполнить свой собственный обработчик до некоторого обработчика в виджетах библиотеки, или вам нужно иметь возможность отменить вызов обработчику виджета условно:
$("button").click(function(e){
if(bSomeConditional)
e.stopImmediatePropagation();//Don't execute the widget handler
}).each(function () {
var aClickListeners = $._data(this, "events").click;
aClickListeners.reverse();
});
Ответ 6
function bindFirst(owner, event, handler) {
owner.unbind(event, handler);
owner.bind(event, handler);
var events = owner.data('events')[event];
events.unshift(events.pop());
owner.data('events')[event] = events;
}
Ответ 7
просто привяжите обработчик нормально, а затем запустите:
element.data('events').action.reverse();
так, например:
$('#mydiv').data('events').click.reverse();
Ответ 8
Вы можете попробовать что-то вроде этого:
/**
* Guarantee that a event handler allways be the last to execute
* @param owner The jquery object with any others events handlers $(selector)
* @param event The event descriptor like 'click'
* @param handler The event handler to be executed allways at the end.
**/
function bindAtTheEnd(owner,event,handler){
var aux=function(){owner.unbind(event,handler);owner.bind(event,handler);};
bindAtTheStart(owner,event,aux,true);
}
/**
* Bind a event handler at the start of all others events handlers.
* @param owner Jquery object with any others events handlers $(selector);
* @param event The event descriptor for example 'click';
* @param handler The event handler to bind at the start.
* @param one If the function only be executed once.
**/
function bindAtTheStart(owner,event,handler,one){
var eventos,index;
var handlers=new Array();
owner.unbind(event,handler);
eventos=owner.data("events")[event];
for(index=0;index<eventos.length;index+=1){
handlers[index]=eventos[index];
}
owner.unbind(event);
if(one){
owner.one(event,handler);
}
else{
owner.bind(event,handler);
}
for(index=0;index<handlers.length;index+=1){
owner.bind(event,ownerhandlers[index]);
}
}
Ответ 9
У меня такая же проблема, и я нашел эту тему. вышеупомянутые ответы могут решить эту проблему, но я не думаю, что они хорошие планы.
Давайте подумаем о реальном мире.
если мы используем эти ответы, мы должны изменить наш код. вы должны изменить свой стиль кода. что-то вроде этого:
оригинал:
$('form').submit(handle);
хак:
bindAtTheStart($('form'),'submit',handle);
со временем подумайте о своем проекте. код уродливый и трудно читаемый! Причина anthoer проста всегда лучше. если у вас есть 10 bindAtTheStart, он может не содержать ошибок. если у вас есть 100 bindAtTheStart, вы действительно уверены, что сможете сохранить их в правильном порядке?
поэтому, если вам нужно связать одни и те же события multiple.I думаю, что лучший способ - это управлять загрузкой js файла или js-кода. jquery может обрабатывать данные событий в виде очереди. заказ является первым-в, первым выходом. вам не нужно менять какой-либо код. просто измените порядок загрузки.
Ответ 10
Здесь мой снимок, охватывающий разные версии jQuery:
// Binds a jQuery event to elements at the start of the event chain for that type.
jQuery.extend({
_bindEventHandlerAtStart: function ($elements, eventType, handler) {
var _data;
$elements.bind(eventType, handler);
// This bound the event, naturally, at the end of the event chain. We
// need it at the start.
if (typeof jQuery._data === 'function') {
// Since jQuery 1.8.1, it seems, that the events object isn't
// available through the public API `.data` method.
// Using `$._data, where it exists, seems to work.
_data = true;
}
$elements.each(function (index, element) {
var events;
if (_data) {
events = jQuery._data(element, 'events')[eventType];
} else {
events = jQuery(element).data('events')[eventType];
}
events.unshift(events.pop());
if (_data) {
jQuery._data(element, 'events')[eventType] = events;
} else {
jQuery(element).data('events')[eventType] = events;
}
});
}
});
Ответ 11
В некоторых особых случаях, когда вы не можете изменить способ привязки событий кликов (привязки событий сделаны из других кодов), и вы можете изменить элемент HTML, вот возможное решение ( warning: это не рекомендуемый способ привязки событий, другие разработчики могут вас убить):
<span onclick="yourEventHandler(event)">Button</span>
С помощью этого способа привязки сначала будет добавлен обработчик событий, поэтому он будет выполнен первым.
Ответ 12
JQuery 1.5 вводит promises, и здесь простейшая реализация, которую я видел, контролирует порядок выполнения. Полная документация на http://api.jquery.com/jquery.when/
$.when( $('#myDiv').css('background-color', 'red') )
.then( alert('hi!') )
.then( myClickFunction( $('#myID') ) )
.then( myThingToRunAfterClick() );