web-dev-qa-db-fra.com

Empêcher le déclenchement de l'événement de flou si l'un de ses enfants reçoit le focus

J'ai un div sur une page qui affiche des informations sur une catégorie particulière (image, nom, etc.).

Lorsque je clique sur l'image d'édition, elle met la catégorie en mode édition, ce qui me permet de mettre à jour le nom. Comme vous pouvez le voir sur l'image ci-dessous, cela montre que "Soupe" est actuellement en mode édition, les autres sont en mode d'affichage normal. Tout cela fonctionne comme prévu avec les boutons d'annulation/sauvegarde qui font tout correctement. (J'ai essayé d'ajouter une image mais je ne me laissais pas, j'ai besoin de plus d'amour)

Cependant une fois en mode édition si je clique ailleurs sur la page (en dehors de la div) le résultat attendu serait que la catégorie de soupe retournerait en mode affichage. Lors d'un événement qui se déclenche, cela devrait également me permettre de demander s'ils voulaient enregistrer les modifications.

J'ai donc décidé de créer un événement flou sur la div parent "soupes". Cela fonctionne comme prévu si je clique n'importe où sur la page, mais si je clique sur l'élément intérieur de la div, cela provoque également le déclenchement de l'événement de flou des parents, ce qui fait revenir la catégorie en mode affichage.

Alors, existe-t-il un moyen d'empêcher le parent div de déclencher l'événement flou si l'un de ses enfants reçoit le focus?

<div tabindex="-1" onblur="alert('outer')">
    <input type="text" value="Soup" />
</div>

Je viens d'écrire le code sans compilateur, donc je ne sais pas si cela fonctionne, mais avec ça j'espère que vous avez l'idée.

J'utilise Knockout.js pour mettre à jour l'interface graphique à la volée, mais cela ne devrait pas affecter cette réponse, je n'aurais pas pensé.

26
Thwaitesy

J'ai dû résoudre ce problème auparavant. Je ne sais pas si c'est la meilleure solution, mais c'est ce que j'ai fini par utiliser.

Étant donné que l'événement click se déclenche après le flou, il n'y a aucun moyen (cross-browser, fiable) de dire quel élément gagne en focus.

Mousedown, cependant, se déclenche avant le flou. Cela signifie que vous pouvez placer un drapeau dans la souricière des éléments de vos enfants et interroger ce drapeau dans le flou de vos parents.

Exemple de travail: http://jsfiddle.net/L5Cts/

Notez que vous devrez également gérer keydown (et vérifier tab/shift-tab) si vous voulez également attraper les flous causés par le clavier.

34
jbabey

Je ne pense pas qu'il y ait de garantie mousedown se produira avant les événements de focus dans tous les navigateurs, donc une meilleure façon de gérer cela pourrait être d'utiliser evt.relatedTarget . Pour l'événement focusin, la propriété eventTarget est une référence à l'élément qui perd actuellement le focus . Vous pouvez vérifier si cet élément est un descendant du parent, et si ce n'est pas le cas, vous savez que le focus entre le parent de l'extérieur. Pour l'événement focusout, relatedTarget est une référence à l'élément qui reçoit actuellement le focus . Utilisez la même logique pour déterminer si le focus quitte complètement le parent:

const parent = document.getElementById('parent');

parent.addEventListener('focusin', e => {
    const enteringParent = !parent.contains(e.relatedTarget);

    if (enteringParent) {
        // do things in response to focus on any child of the parent or the parent itself
    }
});

parent.addEventListener('focusout', e => {
    const leavingParent = !parent.contains(e.relatedTarget);

    if (leavingParent) {
        // do things in response to fully leaving the parent element and all of its children
    }
});
10
Rob Allsopp