187 votes

problème de commande de onclick() et onblur()

J'ai un champ de saisie qui fait apparaître un menu déroulant personnalisé. Je voudrais la fonctionnalité suivante :

  • Lorsque l'utilisateur clique n'importe où en dehors du champ de saisie, le menu doit être supprimé.
  • Si, plus précisément, l'utilisateur clique sur un div à l'intérieur du menu, ce dernier doit être supprimé, et un traitement spécial doit être effectué en fonction de la division sur laquelle on a cliqué.

Voici ma mise en œuvre :

Le champ de saisie a un onblur() qui supprime le menu (en définissant la valeur de l'événement innerHTML à une chaîne vide) lorsque l'utilisateur clique en dehors du champ de saisie. Les divs à l'intérieur du menu ont également onclick() les événements qui exécutent le traitement spécial.

Le problème est que le onclick() ne se déclenchent jamais lorsque l'on clique sur le menu, car le champ d'entrée onblur() se déclenche en premier et supprime le menu, y compris l'option onclick() s !

J'ai résolu le problème en séparant les divs du menu. onclick() en onmousedown() y onmouseup() et la mise en place d'un drapeau global lors de l'abaissement de la souris, qui est effacé lors du relèvement de la souris, de manière similaire à ce qui a été suggéré dans le document intitulé cette réponse . Parce que onmousedown() incendies avant onblur() l'indicateur de validité sera activé dans onblur() si l'on clique sur l'une des divisions du menu, mais pas si l'on clique ailleurs sur l'écran. Si le menu a été cliqué, je retourne immédiatement de la page onblur() sans effacer le menu, puis attendez que le bouton onclick() pour se déclencher, à ce moment-là je peux supprimer le menu en toute sécurité.

Existe-t-il une solution plus élégante ?

Le code ressemble à quelque chose comme ceci :

<div class="menu" onmousedown="setFlag()" onmouseup="doProcessing()">...</div>
<input id="input" onblur="removeMenu()" ... />

var mouseflag;

function setFlag() {
    mouseflag = true;
}

function removeMenu() {
    if (!mouseflag) {
        document.getElementById('menu').innerHTML = '';
    }
}

function doProcessing(id, name) {
    mouseflag = false;
    ...
}

247voto

johnbakers Points 12527

J'avais exactement le même problème que vous, mon IU est conçu exactement comme vous le décrivez. J'ai résolu le problème en remplaçant simplement le onClick pour les éléments de menu avec un onMouseDown . Je n'ai rien fait d'autre. onMouseUp sans drapeaux. Cela a permis de résoudre le problème en laissant le navigateur réorganiser automatiquement l'ordre en fonction de la priorité de ces gestionnaires d'événements, sans que je n'aie à faire de travail supplémentaire.

Y a-t-il une raison pour laquelle cela n'aurait pas également fonctionné pour vous ?

187voto

Ian MacFarlane Points 940

onClick ne doit pas être remplacé par onMouseDown .

Bien que cette approche fonctionne en quelque sorte les deux sont des événements fondamentalement différents qui suscitent des attentes différentes aux yeux de l'utilisateur. Utilisation de onMouseDown au lieu de onClick va ruiner la prévisibilité de votre logiciel dans ce cas. Ainsi, les deux événements ne sont pas interchangeables.

À titre d'exemple : lorsqu'ils cliquent accidentellement sur un bouton, les utilisateurs s'attendent à pouvoir maintenir le clic de la souris enfoncé, faire glisser le curseur en dehors de l'élément, puis relâcher le bouton de la souris, ce qui n'entraîne finalement aucune action. onClick fait ça. onMouseDown ne permet pas à l'utilisateur de maintenir la souris enfoncée, mais déclenche immédiatement une action, sans aucun recours pour l'utilisateur. onClick est la norme par laquelle nous nous attendons à déclencher des actions sur un ordinateur.

Dans cette situation, appelez event.preventDefault() sur le onMouseDown événement. onMouseDown provoquera un événement de flou par défaut, et ne le fera pas quand preventDefault est appelé. Alors, onClick auront une chance d'être appelés. Un événement de flou se produira quand même, mais seulement après que onClick .

Après tout, le onClick L'événement est une combinaison de onMouseDown y onMouseUp si et seulement si elles apparaissent toutes deux dans le même élément.

2voto

Someone Somewhere Points 2711

Remplacer sur onmousedown con onfocus . Ainsi, cet événement sera déclenché lorsque le focus se trouve dans la zone de texte.

Remplacer sur onmouseup con onblur . Au moment où vous retirez votre focus de la zone de texte, onblur s'exécute.

Je suppose que c'est ce dont vous pourriez avoir besoin.

UPDATE :

quand vous exécutez votre fonction onfocus-->enlevez les classes que vous appliquerez dans onblur et ajoutez les classes que vous voulez exécuter onfocus

et

quand vous exécutez votre fonction onblur-->supprimez les classes que vous allez appliquer dans onfocus et ajoutez les classes que vous voulez faire exécuter en onblur

Je ne vois pas l'utilité des variables de drapeau.

UPDATE 2 :

Vous pouvez utiliser les événements onmouseout et onmouseover.

au passage de la souris -Détecte quand le curseur est au-dessus de lui.

onmouseout -Détecte le départ du curseur.

0voto

Brasil Points 1

remplacer onclick par onfocus

même si le onblur et le onclick ne s'entendent pas très bien, mais évidemment onfocus et oui onblur. puisque même après la fermeture du menu le onfocus est toujours valable pour l'élément cliqué à l'intérieur.

Je l'ai fait et ça a marché.

-10voto

user5271069 Points 1

Vous pouvez utiliser un setInterval à l'intérieur de votre onBlur comme ceci :

<input id="input" onblur="removeMenu()" ... />

function removeMenu() {
    setInterval(function(){
        if (!mouseflag) {
            document.getElementById('menu').innerHTML = '';
        }
    }, 0);
}

le site setInterval supprimera votre onBlur en dehors de la pile d'appels, ajoutez parce que vous avez mis le temps à 0, cette fonction sera appelée immédiatement après que l'autre gestionnaire d'événement ait terminé

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X