2011-11-18 13 views
7

Como ya sabe, los eventos generalmente aparecen en javascript, por lo que el controlador de eventos del elemento que dispara el evento se ejecuta primero, luego se llama al controlador de evento del elemento padre y así sucesivamente. Este comportamiento causa algunos problemas en un proyecto en el que estoy trabajando actualmente, preferiría tener el orden de ejecución invertido.Invertir evento burbujeando en javascript

I figuered encontrar una solución que utiliza los tiempos de espera:

$(element).mouseover(function(){ 
    var that = this; 
    setTimeout(function() { 
     //actual event handler, but references to "this" are replaced with "that" 
    },$(this).parents().length) 
}); 

Así que, básicamente, los controladores de eventos se ejecutan después de un corto tiempo de espera, el tiempo de espera depende de la profundidad del elemento en el DOM-árbol : El controlador de eventos del elemento html se ejecuta de inmediato, el controlador de eventos del elemento del cuerpo se ejecuta después de esperar 1 ms y así sucesivamente. Entonces, el orden de ejecución de los eventos se invierte.

Los resultados de mis primeras pruebas son positivos, pero aún no estoy seguro de si hay algún problema o inconveniente con esta solución. ¿Qué piensas de esta solución? Otras ideas sobre cómo resolver estos problemas también son muy apreciadas.

+1

No entiendo por qué está estableciendo * la cantidad de padres * como * hora en milisegundos * por el tiempo de espera. – pimvdb

+2

Lo está haciendo para asegurarse de que la ejecución del controlador de eventos en el elemento hoja se demorará tanto, que se ejecutará al final de la cadena. – WTK

Respuesta

14

El burbujeo de evento inverso se denomina fase de captura.

ver pasar el DOM event architecture

true como el tercero argumento para Event.addEventListener para que active en fase de captura

el.addEventListener("click", function() { 
    console.log("i run in capture"); 
}, true); 

Por supuesto que no va a funcionar en plataformas heredadas. Necesitará un ajuste de eventos DOM3 para emular el sistema de eventos. Siéntase libre de contribuir al DOM-shim

+0

Sí, claro, excepto que no está implementado en todos los navegadores. Vea aquí http://www.quirksmode.org/js/events_order.html – WTK

+1

@WTK ¿A quién le importan las plataformas heredadas? – Raynos

+3

clientes @Raynos ^^ –

0

Veo que una gran desventaja de su solución es que, para cada evento manejado, tiene que recorrer DOM hacia arriba comenzando con this para establecer el número de padres.

Atravesado de tal manera en cada controlador de eventos = bajo rendimiento.

+0

Cada vez que se desencadena un evento, se ejecuta desde la raíz del documento hasta el elemento que desencadenó el evento y luego hasta la raíz. Hacer un viaje extra hasta la raíz del documento en el código de su manejador no tomará una cantidad excesiva de tiempo. –

0

Puede intentar emularlo, pero probablemente le pueda pasar un montón de problemas.

Aquí hay un ejemplo muy simple (y en jsfiddle). La idea es agregar callbacks de cada evento y llamarlos en orden inverso en el controlador de eventos document (también borramos nuestra lista, para asegurar una nueva cola en el siguiente clic).

<div id="a"> 
    <div id="b"> 
     <a href="/test">Click Me!</a> 
    </div> 
</div> 
var cb = []; 

$(document).click(function(evt){ 

    cb.unshift(function(){ 
     console.log('document'); 
    }); 
    var i; 
    for(i=0; i<cb.length; ++i){ 
     cb[i].call(null, evt); 
    } 
    cb = []; 
}); 

$("#a").click(function(){ 
    cb.unshift(function(){ 
     console.log('div#a'); 
    }); 
}); 

$("#b").click(function(){ 
    cb.unshift(function(){ 
     console.log('div#b'); 
    }); 
}); 

$('a').click(function(evt){ 
    cb.unshift(function(evt){ 
     evt.preventDefault(); 
     console.log('a'); 
    }); 
}); 

Tal vez usted necesita para cambiar su diseño? ¿Podría publicar más información, por qué necesita captura de eventos?

+0

Gracias por su respuesta. La razón por la que necesito esta ejecución del manejador de eventos inversos es bastante complicada y difícil de explicar en pocas palabras. Básicamente, tengo manejadores de mouseover para diferentes elementos de un documento html arbitrario. Usualmente, los manejadores de eventos de los elementos externos se ejecutan primero, porque mueves el puntero del mouse sobre los elementos externos antes de llegar a los elementos internos. Pero en los elementos que contienen elementos internos sin ningún relleno, esto falla porque no tienes que hacerlo. mover sobre los elementos externos para llegar a los internos. Así que quiero invertir el orden para un comportamiento consistente – Simon

+0

Hmmm ... siempre podría utilizar algún tipo de 'herencia', como aquí: http://jsfiddle.net/GEFAq/ 2/Y debería funcionar (el trigger es sincrónico, hasta donde yo veo). Este es un concepto básico: en el gestor de elementos detener la propagación y desencadenar el mismo evento en el elemento padre antes de realizar cualquier otra acción. –

+0

Pero, si realmente no te importan los navegadores antiguos, entonces no te molestes y ve con la solución @Raynos :) –