J'ai un champ de saisie qui fait apparaître un menu déroulant personnalisé. Je souhaite la fonctionnalité suivante:
- Lorsque l'utilisateur clique n'importe où en dehors du champ de saisie, le menu doit être supprimé.
- Si, plus spécifiquement, l'utilisateur clique sur un div dans le menu, le menu doit être supprimé et un traitement spécial doit avoir lieu en fonction du div sur lequel l'utilisateur a cliqué.
Voici ma mise en œuvre:
Le champ de saisie a un onblur()
événement qui supprime le menu (en définissant son parent innerHTML
sur une chaîne vide) chaque fois que l'utilisateur clique en dehors du champ de saisie. Les div à l'intérieur du menu ont également des onclick()
événements qui exécutent le traitement spécial.
Le problème est que les onclick()
événements ne se déclenchent jamais lorsque l'utilisateur clique sur le menu, car le champ de saisie se onblur()
déclenche en premier et supprime le menu, y compris le onclick()
s!
J'ai résolu le problème en se divisant le menu divs' onclick()
en onmousedown()
et des onmouseup()
événements et la fixation d' un indicateur global sur le bas de la souris qui est effacée sur souris vers le haut, semblable à ce qui a été suggéré dans cette réponse . Parce que se onmousedown()
déclenche avant onblur()
, le drapeau sera activé onblur()
si l'un des divs de menu a été cliqué, mais pas si quelque part ailleurs sur l'écran était. Si le menu a été cliqué, je reviens immédiatement de onblur()
sans supprimer le menu, puis attendez que le onclick()
se déclenche, à quel point je peux supprimer le menu en toute sécurité.
Existe-t-il une solution plus élégante?
Le code ressemble à 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;
...
}
onmousedown
soit exécuté avantonblur
Testé dans Firefox, Chrome et Internet Explorer.onMouseDown
avecevent.preventDefault()
etonClick
avec l'action souhaitée.onClick
ne doit pas être remplacé paronMouseDown
.Bien que cette approche fonctionne quelque peu , les deux sont des événements fondamentalement différents qui ont des attentes différentes aux yeux de l'utilisateur. Utiliser
onMouseDown
au lieu deonClick
ruinerait la prévisibilité de votre logiciel dans ce cas. Ainsi, les deux événements ne sont pas interchangeables.Pour illustrer: en cliquant 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 et relâcher le bouton de la souris, ce qui n'entraînera finalement aucune action.
onClick
est ce que ca.onMouseDown
ne permet pas à l'utilisateur de maintenir la souris enfoncée, et à la place déclenchera 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, faites appel
event.preventDefault()
à l'onMouseDown
événement.onMouseDown
provoquera un événement de flou par défaut, et ne le fera pas lors de l'preventDefault
appel. Ensuite,onClick
aura une chance d'être appelé. Un événement de flou se produira toujours, seulement aprèsonClick
.Après tout, l'
onClick
événement est une combinaison deonMouseDown
etonMouseUp
, si et seulement si les deux se produisent dans le même élément.la source
event.preventDefault()
suronMouseDown
événement, mononFocus
événement ne s'appelle pasRemplacez
onmousedown
paronfocus
. Donc, cet événement sera déclenché lorsque le focus est à l'intérieur de la zone de texte.Remplacez
onmouseup
paronblur
. Dès que vous retirez votre focus de la zone de texte, onblur s'exécutera.Je suppose que c'est ce dont vous pourriez avoir besoin.
MISE À JOUR :
lorsque vous exécutez votre fonction onfocus -> supprimez les classes que vous allez appliquer dans onblur et ajoutez les classes que vous souhaitez exécuter sur le focus
et
lorsque vous exécutez votre fonction onblur -> supprimez les classes que vous allez appliquer dans onfocus et ajoutez les classes que vous souhaitez exécuter sur le flou
Je ne vois aucun besoin de variables d'indicateur.
MISE À JOUR 2:
Vous pouvez utiliser les événements à la souris et à la souris
onmouseover -Détecte quand le curseur est dessus.
onmouseout -Détecte le départ du curseur.
la source
onmousedown()
etonmouseup()
dans le menu, pas la zone de texte / champ de saisie.Une solution plus élégante (mais probablement moins performante):
Au lieu d'utiliser le onblur de l'entrée pour supprimer le menu, utilisez
document.onclick
, qui se déclenche aprèsonblur
.Cependant, cela signifie également que le menu est supprimé lorsque vous cliquez sur l'entrée elle-même, ce qui est un comportement indésirable. Définissez un
input.onclick
avecevent.stopPropagation()
pour éviter de propager les clics vers l'événement de clic de document.la source
changer onclick par onfocus
même si onblur et onclick ne s'entendent pas très bien, mais évidemment onfocus et oui onblur. car même après la fermeture du menu, onfocus est toujours valide pour l'élément cliqué à l'intérieur.
Je l'ai fait et ça a marché.
la source
Vous pouvez utiliser une
setInterval
fonction dans votreonBlur
gestionnaire, comme ceci:la
setInterval
fonction supprimera votreonBlur
fonction de la pile d'appels, ajoutez parce que vous définissez l'heure à 0, cette fonction sera appelée immédiatement après la fin d'un autre gestionnaire d'événementsla source
setInterval
est une mauvaise idée, vous ne l'annulez jamais, donc cela exécutera continuellement votre fonction et provoquera probablement l'utilisation de max cpu par votre site. Utilisez à lasetTimeout
place si vous allez utiliser cette technique (que je ne recommande pas). Faire dépendre votre application du calendrier de certains événements est une entreprise risquée.setTimeout
passetInterval
), mais j'ai dû l'augmenter jusqu'à250
ms avant que le timing ne se produise dans le bon ordre. Ce bogue existera probablement toujours sur les appareils plus lents et rend le retard perceptible. J'ai essayéonMouseDown
et ça marche bien. Je me demande s'il a également besoin des événements tactiles.