Tengo un menú flotante bastante simple, y estoy tratando de descubrir cómo lidiar con el tiempo.

El objetivo es retrasar el evento mouseleave en 500 y / o no reaccionar a los pases rápidos sobre otros elementos del menú.

La función básica:

$('.button').on({
  mouseenter: function () {
    $(this).children('.menu').addClass('open');
  },
  mouseleave: function() {
    $(this).children('.menu').removeClass('open');
  }, 
});

El principal problema con esto es la brecha de píxeles entre el botón y el menú: cuando un usuario mueve el mouse hacia el menú, entonces se activa la función mouseleave.

Una segunda molestia es que al pasar el mouse rápidamente sobre los botones hermanos también activan sus funciones mouseenter.

También lo intenté pero no reaccioné ...

mouseleave: function() {

  setTimeout(function () {
    $(this).children('.menu').removeClass('open');
  }, 500);},

});

Y también he intentado usar

.delay(500).queue(function(){
  $(this).removeClass("open").dequeue();

Pero me parece inestable

console.log($.ui.version) imprime 1.11.4

0
petergus 4 abr. 2017 a las 21:09

2 respuestas

La mejor respuesta

Considere esperar los 500 ms, luego verifique si la condición que está viendo (suspendida o no) sigue siendo cierta.

Si es así, luego tome las medidas apropiadas.

$('.button').on({
  mouseenter: function() {
    waitEnterExit(this, true);
  },
  mouseleave: function() {
    waitEnterExit(this, false);
  },
});


function waitEnterExit(el, inside) {
  var button = $(el);

  setTimeout(function() {
    var hovered = button.is(':hover');

    if (hovered && inside)
      button.children('.menu').addClass('open');
    else if (!hovered && !inside)
      button.children('.menu').removeClass('open');
  }, 500);
}
p {
  display: none;
}

.open {
  display: block;
}

.button {
  border: 1px solid red;
  margin-bottom: .5em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class=button>1
  <p class=menu>inner</p>
</div>
<div class=button>2
  <p class=menu>inner</p>
</div>
<div class=button>3
  <p class=menu>inner</p>
</div>
<div class=button>4
  <p class=menu>inner</p>
</div>
1
Paul Roub 4 abr. 2017 a las 18:21

La respuesta anterior es correcta, pero solo quiero hacer una nota (no puedo comentar, debido a la baja reputación, así que la dejo como respuesta).

Tenga en cuenta que, en este caso, el mouseleave que utilizó no funcionará para eliminar las clases.

mouseleave: function() {
  //Won't remove .open
  setTimeout(function () {
    $(this).children('.menu').removeClass('open');
  }, 500);},
});

Lo que sucede es que $ (this) en la función setTimeout es la ventana, no su botón. Si desea apuntar su botón, deberá pasarlo para la función setTimeout. Una forma de hacerlo es creando una variable con esto . Puede probarlo llamando a console.log con $ (this) dentro y fuera de la función setTimeout para ver qué se imprime en la consola.

mouseleave: function() {
  // caller now is the equivalent to this
  var caller = this;
  setTimeout(function () {
    // $(this) equivalent to the .button in this case
    $(caller).children('.menu').removeClass('open');
  }, 500);},
});
1
JulyOrdinary 5 abr. 2017 a las 05:48