Pregunta

Tengo una página web con DIV con un controlador mouseover que pretende mostrar una burbuja de información emergente. No quiero que se vea más de una burbuja de información a la vez. Pero cuando el usuario mueve el mouse rápidamente sobre dos elementos, a veces obtengo dos burbujas. Esto no debería ocurrir, porque el código para mostrar una ventana emergente cancela la ventana emergente anterior.

Si se tratara de un sistema multiproceso, entonces el problema sería obvio: hay dos subprocesos que intentan mostrar una ventana emergente, y ambas cancelan las ventanas emergentes existentes y luego muestran sus propias ventanas emergentes. Pero asumí que JavaScript siempre se ejecuta en un solo hilo, lo que evitaría esto. ¿Me equivoco? ¿Los controladores de eventos se ejecutan de forma asíncrona, en cuyo caso necesito acceso sincronizado a los datos compartidos, o debo buscar errores en el código de la biblioteca para cancelar ventanas emergentes?

Editado para agregar:

  • La biblioteca en cuestión es SIMILE Timeline y su biblioteca Ajax;
  • El controlador de eventos llama a SimileAjax.DOM.cancelEvent (domEvt) , que asumo que en función del nombre cancela el burbujeo de eventos;
  • Para hacer las cosas más complicadas, lo que estoy haciendo en realidad es comenzar un tiempo de espera que, si no se cancela con un moustout , muestra la ventana emergente, con la intención de evitar que las ventanas emergentes parpadeen de manera molesta. pero molesto teniendo el efecto contrario.

Tendré otro golpe y veré si puedo averiguar dónde me voy mal. :-)

¿Fue útil?

Solución

Sí, Javascript es de un solo hilo. Incluso con navegadores como Google Chrome, hay un hilo por pestaña.

Sin saber cómo intenta cancelar una ventana emergente de otra, es difícil decir cuál es la causa de su problema.

Si sus DIV están anidados uno dentro del otro, puede tener un propagación del evento .

Otros consejos

No conozco la biblioteca que está utilizando, pero si solo está intentando mostrar una información sobre herramientas de somesort a la vez ... use un objeto de peso mosca. Básicamente, un peso mosca es algo que se hace una vez y se usa una y otra vez. Piense en una clase de singleton. Así que usted llama a una clase estáticamente que cuando se invoca por primera vez automáticamente crea un objeto de sí mismo y lo almacena. Una de estas situaciones es que todas las estáticas hacen referencia al mismo objeto y, debido a esto, no se obtienen múltiples información sobre herramientas o conflictos.

Utilizo ExtJS y hacen información sobre herramientas y cuadros de mensajes como elementos de peso mosca. Espero que sus marcos también tengan elementos de peso mosca, de lo contrario, solo tendrá que crear su propio singleton y llamarlo.

Es un solo hilo en los navegadores. Los controladores de eventos se ejecutan de forma asíncrona en un subproceso, el no bloqueo no siempre significa multiproceso. ¿Es uno de tus divs un hijo del otro? Debido a que los eventos se propagan como burbujas en el árbol dom desde el niño hasta el padre.

Similar a lo que dijo pkaeding, es difícil adivinar el problema sin ver su marca y script; sin embargo, me atrevería a decir que no está deteniendo correctamente la propagación del evento y / o que no está ocultando correctamente el elemento existente. No sé si está utilizando un marco o no, pero aquí hay una posible solución utilizando Prototype:

// maintain a reference to the active div bubble
this.oActiveDivBubble = null;

// event handler for the first div
$('exampleDiv1').observe('mouseover', function(evt) {
    evt.stop();
    if(this.oActiveDivBubble ) {
        this.oActiveDivBubble .hide();
    }
    this.oActiveDivBubble = $('exampleDiv1Bubble');
    this.oActiveDivBubble .show();

}.bind(this));

// event handler for the second div
$('exampleDiv2').observe('mouseover'), function(evt) {
    evt.stop();
    if(this.oActiveDivBubble) {
        this.oActiveDivBubble.hide();
    }
    this.oActiveDivBubble = $('exampleDiv2Bubble');
    this.oActiveDivBubble .show();
}.bind(this));

Por supuesto, esto podría generalizarse aún más al obtener todos los elementos con, digamos, la misma clase, iterando a través de ellos, y aplicando la misma función de manejo de eventos a cada uno de ellos.

De cualquier manera, espero que esto ayude.

Para su información: a partir de Firefox 3 hay un cambio bastante relevante para esta discusión: los hilos de ejecución que causan que las solicitudes XMLHttpRequest sincrónicas se separen (es por eso que la interfaz no se congela allí durante las solicitudes sincrónicas) y la ejecución continúa. Al completar la solicitud síncrona, su hilo también continúa. No se ejecutarán al mismo tiempo, sin embargo, basándose en el supuesto de que un solo subproceso se detiene mientras se produce un procedimiento síncrono (solicitud) ya no es aplicable.

Es posible que la pantalla no se actualice lo suficientemente rápido. Dependiendo de la biblioteca JS que esté utilizando, es posible que pueda poner un pequeño retraso en la ventana emergente " mostrar " efecto.

Aquí está la versión de trabajo, más o menos. Al crear elementos, adjuntamos un evento mouseover :

var self = this;
SimileAjax.DOM.registerEvent(labelElmtData.elmt, "mouseover", function (elt, domEvt, target) {
    return self._onHover(labelElmtData.elmt, domEvt, evt);
});

Esto llama a una función que establece un tiempo de espera (los tiempos de espera preexistentes para un elemento diferente se cancelan primero):

MyPlan.EventPainter.prototype._onHover = function(target, domEvt, evt) {            
    ... calculate x and y ...
    domEvt.cancelBubble = true;
    SimileAjax.DOM.cancelEvent(domEvt);
    this._futureShowBubble(x, y, evt);

    return false;
}
MyPlan.EventPainter.prototype._futureShowBubble = function (x, y, evt) {
    if (this._futurePopup) {
        if (evt.getID() == this._futurePopup.evt.getID()) {
            return;
        } else {
            /* We had queued a different event's pop-up; this must now be cancelled. */
            window.clearTimeout(this._futurePopup.timeoutID);
        } 
    }
    this._futurePopup = {
        x: x,
        y: y,
        evt: evt
    };    
    var self = this;
    this._futurePopup.timeoutID =  window.setTimeout(function () {
            self._onTimeout();
    }, this._popupTimeout);
}

Esto a su vez muestra la burbuja si se dispara antes de ser cancelada:

MyPlan.EventPainter.prototype._onTimeout = function () {
    this._showBubble(this._futurePopup.x, this._futurePopup.y, this._futurePopup.evt);

};

MyPlan.EventPainter.prototype._showBubble = function(x, y, evt) {
    if (this._futurePopup) {
        window.clearTimeout(this._futurePopup.timeoutID);
        this._futurePopup = null;
    }        
    ...

    SimileAjax.WindowManager.cancelPopups();
    SimileAjax.Graphics.createBubbleForContentAndPoint(...);
};

Esto parece funcionar ahora. He establecido el tiempo de espera en 200 ms en lugar de 100 ms. No estoy seguro de por qué un tiempo de espera demasiado corto hace que ocurra la burbuja múltiple, pero supongo que la cola de eventos de la ventana o algo podría estar sucediendo mientras se diseñan los elementos recién agregados.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top