change aside all javascript jquery events

javascript - aside - jquery replace html



Cómo ordenar eventos enlazados con jQuery (12)

Digamos que tengo una aplicación web que tiene una página que puede contener 4 bloques de script: la secuencia de comandos que escribo se puede encontrar en uno de esos bloques, pero no sé cuál, que maneja el controlador.

onclick algunos eventos onclick a un botón, pero me parece que a veces se ejecutan en un orden que no esperaba.

¿Hay alguna manera de garantizar el orden o cómo ha manejado este problema en el pasado?


Aquí está mi oportunidad de esto, que cubre diferentes versiones de 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; } }); } });


El método de Dowski es bueno si todas tus devoluciones de llamada van a estar siempre presentes y te alegra que dependan el uno del otro.

Sin embargo, si desea que las devoluciones de llamadas sean independientes entre sí, puede aprovechar el burbujeo y adjuntar eventos posteriores como delegados a elementos principales. Los controladores en los elementos principales se activarán después de los manejadores en el elemento, continuando hasta el documento. Esto es bastante bueno ya que puede usar event.stopPropagation() , event.preventDefault() , etc. para omitir los manejadores y cancelar o cancelar la acción.

$( ''#mybutton'' ).click( function(e) { // Do stuff first } ); $( ''#mybutton'' ).click( function(e) { // Do other stuff first } ); $( document ).delegate( ''#mybutton'', ''click'', function(e) { // Do stuff last } );

O bien, si no le gusta esto, puede usar el complemento bindLast de Nick Leaches para forzar la finalización de un evento: https://github.com/nickyleach/jQuery.bindLast .

O bien, si está utilizando jQuery 1.5, también podría hacer algo inteligente con el nuevo objeto Diferido.


El orden en que se invocan las devoluciones de llamada vinculadas se gestiona mediante los datos de eventos de cada objeto jQuery. No hay funciones (que yo sepa) que le permitan ver y manipular esos datos directamente, solo puede usar bind () y desvincular () (o cualquiera de las funciones auxiliares equivalentes).

El método de Dowski es el mejor; debe modificar las diversas devoluciones de llamada para vincularlas a una secuencia ordenada de eventos personalizados, con la "primera" devolución de llamada vinculada al evento "real". De esa forma, sin importar en qué orden estén vinculados, la secuencia se ejecutará de la manera correcta.

La única alternativa que puedo ver es algo que realmente, realmente, no quiero contemplar: si sabe que la sintaxis vinculante de las funciones puede haber estado vinculada antes que usted, intente desvincular todas esas funciones y luego volver a unirlas en el orden correcto usted mismo. Eso es solo pedir problemas, porque ahora tienes código duplicado.

Sería genial si jQuery le permitiera simplemente cambiar el orden de los eventos enlazados en los datos de eventos de un objeto, pero sin escribir algún código para enganchar en el núcleo de jQuery que no parece posible. Y probablemente haya implicaciones de permitir esto que no he pensado, así que tal vez sea una omisión intencional.


En algunos casos especiales, cuando no puede cambiar la forma en que se enlazan los eventos de clic (los enlaces de evento están hechos de códigos de otros), y puede cambiar el elemento HTML, aquí hay una posible solución ( advertencia : esta no es la manera recomendada de vincular eventos, otros desarrolladores pueden asesinarlo por esto):

<span onclick="yourEventHandler(event)">Button</span>

Con esta forma de encuadernación, primero se agregará su evento, por lo que se ejecutará primero.


He intentado durante años generalizar este tipo de proceso, pero en mi caso solo me preocupaba el orden del primer oyente del evento en la cadena.

Si es de alguna utilidad, aquí está mi complemento jQuery que vincula un detector de eventos que siempre se desencadena antes que cualquier otro:

** ACTUALIZADO en línea con los cambios de jQuery (gracias a 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);

Cosas a tener en cuenta:

  • Esto no ha sido probado completamente.
  • Se basa en que las partes internas del marco jQuery no cambian (solo se ha probado con 1.5.2).
  • No necesariamente se activará antes de los detectores de eventos que están vinculados de cualquier manera que no sea como un atributo del elemento de origen o utilizando jQuery bind () y otras funciones asociadas.

JQuery 1.5 introduce promesas, y aquí está la implementación más simple que he visto para controlar el orden de ejecución. Documentación completa en http://api.jquery.com/jquery.when/

$.when( $(''#myDiv'').css(''background-color'', ''red'') ) .then( alert(''hi!'') ) .then( myClickFunction( $(''#myID'') ) ) .then( myThingToRunAfterClick() );


Puedes probar algo como esto:

/** * 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]); } }


Si el orden es importante, puede crear sus propios eventos y vincular devoluciones de llamadas para que se disparen cuando esos eventos se desencadenan por otras devoluciones de llamada.

$(''#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; });

Algo así al menos.


Tenga en cuenta que en el universo de jQuery esto debe implementarse de forma diferente a partir de la versión 1.8. La siguiente nota de la versión es del blog de jQuery:

.data ("eventos"): jQuery almacena sus datos relacionados con eventos en un objeto de datos llamado eventos (wait for it) en cada elemento. Esta es una estructura de datos interna, por lo que en 1.8 se eliminará del espacio de nombre de datos del usuario para que no entre en conflicto con elementos del mismo nombre. Aún se puede acceder a los datos de eventos de jQuery a través de jQuery._data (elemento, "eventos")

Tenemos control completo del orden en que los manejadores se ejecutarán en el universo jQuery . Ricoo señala esto arriba. No parece que su respuesta le haya ganado mucho amor, pero esta técnica es muy útil. Considere, por ejemplo, cada vez que necesite ejecutar su propio controlador antes de algún controlador en un widget de biblioteca, o necesita tener la capacidad de cancelar la llamada al controlador del widget de forma condicional:

$("button").click(function(e){ if(bSomeConditional) e.stopImmediatePropagation();//Don''t execute the widget''s handler }).each(function () { var aClickListeners = $._data(this, "events").click; aClickListeners.reverse(); });


Tengo el mismo problema y encontré este tema. las respuestas anteriores pueden resolver esos problemas, pero no creo que sean buenos planes.

pensemos en el mundo real.

si usamos esas respuestas, tenemos que cambiar nuestro código. tienes que cambiar tu estilo de código algo como esto:

original:

$(''form'').submit(handle);

cortar:

bindAtTheStart($(''form''),''submit'',handle);

a medida que pasa el tiempo, piense en su proyecto. ¡el código es feo y difícil de leer! la razón de anthoer es simple es siempre mejor. si tiene 10 bindAtTheStart, es posible que no tenga errores. si tiene 100 bindAtTheStart, ¿está seguro de poder mantenerlos en el orden correcto?

así que si tiene que vincular los mismos eventos múltiples. Creo que la mejor manera es controlar el orden de carga js-file o js-code. jquery puede manejar datos de eventos como cola. el orden es primero en entrar, primero en salir. no es necesario cambiar ningún código. solo cambia el orden de carga.


simplemente enlace el controlador normalmente y luego ejecute:

element.data(''events'').action.reverse();

así por ejemplo:

$(''#mydiv'').data(''events'').click.reverse();


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; }