Problème avec jQuery activation de la flèche de la souris lorsque le conteneur a une boîte de sélection

J'ai deux conteneurs – l'un est imbriqué à l'intérieur d'un autre. Lorsque je passe sur le parent, je souhaite que le conteneur enfant apparaisse. Quand je me déplace, je veux que le conteneur enfant se fadeout. Le problème que j'en ai est que le conteneur enfant comporte un formulaire contenant une "boîte de sélection". Lorsque l'utilisateur sélectionne la boîte de sélection – l'événement de l'écran de souris est accidentellement déclenché.

Comment puis-je empêcher la boîte de sélection de déclencher l'événement mouseleave?

Vous pouvez voir mon code de travail ici: http://jsfiddle.net/rsturim/9TZyh/3/

Voici un résumé de mon script:

$('#parent-container').live("mouseenter", function () { var $this = $(this), $selectOptionsContainer = $this.find('#child-container'); $selectOptionsContainer.stop().fadeTo('slow', 1.0); }).live("mouseleave", function (e) { var $this = $(this), $selectOptionsContainer = $this.find('#child-container'); $selectOptionsContainer.stop().hide(); }); 

Edit : apparaît bien dans les navigateurs basés sur WebKit. Échec dans Firefox et IE7-IE9.

Puisque les événements mouseleave et mouseenter ne sont pas standard, vous pouvez obtenir de tels délais ici et là. La seule méthode que je peux proposer pour corriger cela est d'utiliser certains hacks. Voici http://jsfiddle.net/mPDcu/1/ version améliorée de votre code.

 var selectOpened = false; $('#select-grind-type').click(function(e){ selectOpened = !selectOpened; e.stopPropagation(); }); $('body').click(function(){ if (selectOpened) { selectOpened = false; } }) $('#parent-container').on("mouseenter", function() { var $this = $(this), $selectOptionsContainer = $this.find('#child-container'); $selectOptionsContainer.stop().fadeTo('slow', 1.0); }).live("mouseleave", function(e) { if (!selectOpened) { var $this = $(this), $selectOptionsContainer = $this.find('#child-container'); $selectOptionsContainer.stop().hide(); } }); 

Dans la plupart des cas, vous devriez simplement vérifier si la cible de l'événement était un élément sélectionné et ne pas continuer dans le cas où il ne l'était pas. Il semble beaucoup plus propre que la solution acceptée, et a bien fonctionné dans mon cas.

J'ai modifié le violon: http://jsfiddle.net/Dygerati/uj3ZC/5/

 $('#parent-container').live("mouseenter", function() { var $this = $(this), $selectOptionsContainer = $this.find('#child-container'); $selectOptionsContainer.stop().fadeTo('slow', 1.0); }).live("mouseleave", function(e) { if(e.target.tagName.toLowerCase() != "select") { var $this = $(this), $selectOptionsContainer = $this.find('#child-container'); $selectOptionsContainer.stop().hide(); } }); 
 $('#parent-container').live("mouseenter", function () { var $this = $(this), $selectOptionsContainer = $this.find('#child-container'); $selectOptionsContainer.stop().fadeTo('slow', 1.0); }).live("mouseleave", function (e) { /* Solution */ if(e.relatedTarget == null) return; /************/ var $this = $(this), $selectOptionsContainer = $this.find('#child-container'); $selectOptionsContainer.stop().hide(); }); 

J'ai eu le même problème dans un projet dans lequel je contribue et les autres réponses ne fonctionnent pas bien pour moi. Ma solution délicate était de vérifier si la position de la souris à l'intérieur de l'objet événement se trouvait dans le conteneur parent. Fonctionne très bien!

 var layer = $('#parent-container'), layerPos = {}; $(layer).mouseenter(function () { var $this = $(this), $selectOptionsContainer = $this.find('#child-container'); $selectOptionsContainer.stop().fadeTo('slow', 1.0, function(){ layerPos.x = { min: $(layer).offset().left, max: $(layer).offset().left + $(layer).width() }; layerPos.y = { min: $(layer).offset().top, max: $(layer).offset().top + $(layer).height() }; }); }) $(layer).mouseleave(function(e) { // check if event mouse position is inside parent container var x_con = e.pageX >= layerPos.x.min && e.pageX <= layerPos.x.max; var y_con = e.pageY >= layerPos.y.min && e.pageY <= layerPos.y.max; if ( x_con && y_con ) { return false; } var $this = $(this), $selectOptionsContainer = $this.find('#child-container'); $selectOptionsContainer.stop().hide(); }); 

Vous pouvez également vérifier la version du navigateur pour éviter ce code à exécuter dans les navigateurs qui prennent en charge cette fonctionnalité comme Chrome.

Cela résout partiellement le problème. Déconseillez l'événement mouseleave lorsque la case select gagne du focus et liez-la quand elle perd la mise au point.

http://jsfiddle.net/9TZyh/5/

 $('#parent-container').live("mouseenter", function() { var $this = $(this); $selectOptionsContainer = $this.find('#child-container'); $selectOptionsContainer.stop().fadeTo('slow', 1.0); }).live("mouseleave",focusOut); $("#select-grind-type").live("focus",function(){ $('#parent-container').die("mouseleave"); }); $("#select-grind-type").live("focusout change",function(){ $('#parent-container').live("mouseleave",focusOut); }); function focusOut(e) { var $this = $(this), $selectOptionsContainer = $this.find('#child-container'); $selectOptionsContainer.stop().hide(); } 

Si cela ne vous dérange pas de ne pas fonctionner dans certains anciens navigateurs, vous pouvez le faire avec CSS rapidement:

 #parent-container { } #child-container { opacity:0; -webkit-transition:opacity 1s ease-in; -moz-transition:opacity 1s ease-in; } #parent-container:hover #child-container {{ opacity:1; -webkit-transition:opacity 1s ease-out; -moz-transition:opacity 1s ease-out; } 

Ces gars vous donnent une alternative pratique, mais ils ont aussi des problèmes. Par exemple, si vous quittez la boîte externe pendant que la boîte combinée est encore ouverte, elle ne disparaîtra pas. Je vous recommande une alternative beaucoup plus facile qui corrigera également ce bug.

Au lieu de penser à l'événement de la flèche de souris de la boîte intérieure, pourquoi ne vous permettez pas de penser à l'inverse? Je veux dire, en sortant de la boîte intérieure, cela signifie également entrer dans un autre conteneur. Ainsi, vous pouvez faire outerContainer.mouseenter(function(){ hideInnerBox() }); 🙂

De toute évidence, à cet effet, la boîte intérieure ne devrait pas être un enfant de la boîte extérieure, même si elle apparaît visuellement (le positionnement css peut être utilisé pour l'atteindre)

Donc, j'ai rencontré un problème similaire avec un <select> imbriqué dans un conteneur et j'ai rencontré cette question. Voici ce que j'ai fini par faire.

  $("#container").mouseover(function(e){ var t = $(this); t.addClass('active'); var offset = t.offset(); var xMin = offset.left; var yMin = offset.top; var xMax = xMin + t.innerWidth(); var yMax = yMin + t.innerHeight(); t.parent().mousemove(function(e){ if(e.pageX < xMin || e.pageX > xMax-2 || e.pageY < yMin || e.pageY > yMax ){ t.removeClass('active'); // unbind this event $(this).unbind('mousemove'); } }); }); 

Fondamentalement, lorsque vous passez la souris sur le conteneur, nous collectons ses limites et commençons à vérifier si oui ou non la souris est sur l'élément. Lorsque nous savons que la souris est allée, nous mousemove écouteur mousemove .

Je ferais un jsfiddle pour toi, mais ça marche si lentement aujourd'hui!

J'espère que cela pourra aider.

Vous ne devez vérifier que l'élément actuel est un descendant de votre conteneur.

Si donc, avancer le manipulateur.

Voir: jquery descendant

Exemple:

 ContainerElement.mouseleave(function (e) { if (ContainerElement.has(e.fromElement).length > 0) return; // Do your Stuff });