Déterminer sur quel élément se trouve le pointeur de la souris en Javascript

111

Je veux une fonction qui me dit sur quel élément se trouve le curseur de la souris.

Ainsi, par exemple, si la souris de l'utilisateur est sur cette zone de texte (avec id wmd-input), l'appel window.which_element_is_the_mouse_on()sera fonctionnellement équivalent à$("#wmd-input")

Tom Lehman
la source

Réponses:

148

DEMO

Il y a une fonction vraiment cool appelée document.elementFromPointqui fait ce que cela ressemble.

Ce dont nous avons besoin est de trouver les coordonnées x et y de la souris, puis de l'appeler en utilisant ces valeurs:

var x = event.clientX, y = event.clientY,
    elementMouseIsOver = document.elementFromPoint(x, y);

document.elementFromPoint

Objet d'événement jQuery

qwertymk
la source
1
@TikhonJelvis: Eh bien, à partir de là, je vois qu'il est pris en charge sur IE et Firefox. Si vous obtenez ces deux, vous les obtenez généralement tous. MSDN MDN
qwertymk
1
Impressionnant. Existe-t-il un moyen d'obtenir les coordonnées de la souris SANS attraper un événement? (Probablement pas je suppose). Si ce n'est pas possible, alors malheureusement je ne pense pas que cette méthode soit meilleure que event.targetquoi que ce soit
Tom Lehman
1
@HoraceLoeb Il n'est pas possible d'obtenir les coordonnées de la souris sans attraper un événement. voir cette question SO pour plus d'explications
Logan Besecker
2
C'est une façon étrange de le faire. Si vous attrapez un événement, pourquoi ne pas simplement l'utiliser event.target?
pmrotule
3
La réponse n'explique pas ce que eventc'est, et comment il est
devenu
64

Dans les navigateurs plus récents, vous pouvez effectuer les opérations suivantes:

document.querySelectorAll( ":hover" );

Cela vous donnera une liste de nœuds d'éléments sur lesquels la souris se trouve actuellement dans l'ordre du document. Le dernier élément de la liste de nœuds est le plus spécifique, chaque élément précédent doit être un parent, un grand-parent, etc.

Dherman
la source
2
Cela ne semblait pas fonctionner pendant que je traînais un <li>certain temps sur d'autres <li>éléments.
Seiyria
2
J'ai créé un violon avec $(':hover')mais c'est fondamentalement la même chose: jsfiddle.net/pmrotule/2pks4tf6
pmrotule
3
(function(){ var q = document.querySelectorAll(":hover"); return q[q.length-1]; })()
utilisateur
3
J'ai le sentiment que la performance de ceci est horrible. mousemove
Appeler
49

Bien que ce qui suit ne réponde pas réellement à la question, puisqu'il s'agit du premier résultat d'une recherche sur Google (le googleur peut ne pas poser exactement la même question :), j'espère que cela fournira des informations supplémentaires.

Il existe en fait deux approches différentes pour obtenir une liste de tous les éléments sur lesquels la souris se trouve actuellement (pour les navigateurs plus récents, peut-être):

L'approche "structurelle" - Arbre DOM ascendant

Comme dans la réponse de Dherman, on peut appeler

var elements = document.querySelectorAll(':hover');

Cependant, cela suppose que seuls les enfants superposeront leurs ancêtres, ce qui est généralement le cas, mais pas vrai en général, en particulier lorsqu'il s'agit de SVG où des éléments dans différentes branches de l'arborescence DOM peuvent se chevaucher.

L'approche «visuelle» - basée sur le chevauchement «visuel»

Cette méthode utilise document.elementFromPoint(x, y)pour trouver l'élément le plus haut, le masquer temporairement (puisque nous le récupérons immédiatement dans le même contexte, le navigateur ne le rendra pas réellement), puis continuez pour trouver le deuxième élément le plus haut ... Ça a l'air un peu hacky, mais il renvoie ce que vous attendez quand il y a, par exemple, des éléments frères dans un arbre qui s'occluent les uns les autres. Veuillez trouver cet article pour plus de détails,

function allElementsFromPoint(x, y) {
    var element, elements = [];
    var old_visibility = [];
    while (true) {
        element = document.elementFromPoint(x, y);
        if (!element || element === document.documentElement) {
            break;
        }
        elements.push(element);
        old_visibility.push(element.style.visibility);
        element.style.visibility = 'hidden'; // Temporarily hide the element (without changing the layout)
    }
    for (var k = 0; k < elements.length; k++) {
        elements[k].style.visibility = old_visibility[k];
    }
    elements.reverse();
    return elements;
}

Essayez les deux et vérifiez leurs différents retours.

herrlich10
la source
Cela m'a beaucoup aidé. Merci @ herrlich10. Étonnamment, votre code gère également le cas des éléments enfants imbriqués.
Vikram Deshmukh
Ceci est extrêmement utile. Exactement ce que je cherchais. Comme vous l'avez dit, querySelectorAll ne fonctionne pas dans tous les scénarios.
noobsharp
4
@ herrlich10 Cela semble être un polyfill décent pour developer.mozilla.org/en-US/docs/Web/API/Document/… . Si cette API existe dans votre browserSet pris en charge, je pense que vous pouvez l'utiliser.
dherman
Merci pour cela - fonctionne à peu près comme prévu (bien qu'aucun élément ne soit inversé pour la compatibilité avec getElementsFromPoint), mais il est beaucoup plus lent (18 à 20 ms par appel dans mes tests en chrome), ce qui le rend difficile à utiliser dans le scénario que j'avais dans l'esprit (il n'est pas possible de trouver des cibles de dépôt pendant un glissement dans un cas lors de l'utilisation d'une approche plus basique axée sur les événements).
jsdw
1
voir Document.elementsFromPoint(x, y) stackoverflow.com/a/31805883/1059828
Karl Adler
21

elementFromPoint()obtient uniquement le premier élément de l'arborescence DOM. Ce n'est généralement PAS suffisant pour les besoins des développeurs. Pour obtenir plus d'un élément, par exemple à la position actuelle du pointeur de la souris, voici la fonction dont vous avez besoin:

document.elementsFromPoint(x, y) . // mind the 's' in elements

Cela renvoie un tableau de tous les objets élément sous le point donné. Passez simplement les valeurs X et Y de la souris à cette fonction.

Plus d'informations ici: https://developer.mozilla.org/en-US/docs/Web/API/document/elementsFromPoint

Pour les navigateurs très anciens qui ne sont pas pris en charge, vous pouvez utiliser cette réponse comme solution de secours.

Karl Adler
la source
3
Il est bien soutenu maintenant en 2018.
Boy
6

Survolez la bulle des événements, vous pouvez donc placer un seul auditeur sur le corps et attendre qu'ils bouillonnent, puis saisissez le event.targetou event.srcElement:

function getTarget(event) {
    var el = event.target || event.srcElement;
    return el.nodeType == 1? el : el.parentNode;
}

<body onmouseover="doSomething(getTarget(event));">
RobG
la source
Bien que j'utilise moi-même des gestionnaires d'événements universels, cela coûterait plus cher en termes de ressources que document.elementFromPoint(x, y).
John
6

Le code suivant vous aidera à obtenir l'élément du pointeur de la souris. Les éléments résultants s'afficheront dans la console.

document.addEventListener('mousemove', function(e) {
    console.log(document.elementFromPoint(e.pageX, e.pageY)); 
})
saikumar
la source
1
Cela nécessite le déplacement du curseur. Aussi proche que cela puisse être, ce n'est pas ce qui est demandé ici.
Carles Alcolea
Ne fonctionne pas si la page défile. Utilisez e.clientXet à la e.clientYplace (testé sur Firefox 59).
Youen
5

Vous pouvez regarder la cible de l' mouseoverévénement sur un ancêtre approprié:

var currentElement = null;

document.addEventListener('mouseover', function (e) {
    currentElement = e.target;
});

Voici une démo.

Ry-
la source
4
<!-- One simple solution to your problem could be like this: -->

<div>
<input type="text" id="fname" onmousemove="javascript: alert(this.id);" />
<!-- OR -->
<input type="text" id="fname" onclick="javascript: alert(this.id);" />
</div>
<!-- Both mousemove over the field & click on the field displays "fname"-->
<!-- Works fantastic in IE, FireFox, Chrome, Opera. -->
<!-- I didn't test it for Safari. -->
Dip M
la source
3
Je m'excuse pour la mauvaise manière dont vous avez été traité sur votre question (maintenant supprimée). Personnellement, je préférerais que la question ne soit pas supprimée. Alors qu'il était sur le point d'être fermé (injustement, à mon avis), j'avais l'intention de voter pour le rouvrir. Cependant, étant donné le nombre de votes négatifs, je comprends que vous choisissiez de le garder supprimé.
halfer
3

DEMO: D Déplacez votre souris dans la fenêtre de l'extrait de code: D

<script>
document.addEventListener('mouseover', function (e) {
	  console.log ("You are in ",e.target.tagName);
});
</script>

Zibri
la source
1

La cible de l' mousemoveévénement DOM est l'élément DOM le plus haut sous le curseur lorsque la souris se déplace:

(function(){
    //Don't fire multiple times in a row for the same element
    var prevTarget=null;
    document.addEventListener('mousemove', function(e) {
        //This will be the top-most DOM element under cursor
        var target=e.target;
        if(target!==prevTarget){
            console.log(target);
            prevTarget=target;
        }
    });
})();

Ceci est similaire à la solution de @Philip Walton, mais ne nécessite ni jQuery ni setInterval.

Max Heiber
la source
1

Vous pouvez utiliser ce sélecteur pour saper l'objet et le manipuler en tant qu'objet jquery. $(':hover').last();

Serge Gordeev
la source
4
Bienvenue dans Stack Overflow! Veuillez ajouter quelques explications sur les raisons pour lesquelles ce code aide l'OP. Cela aidera à fournir une réponse dont les futurs téléspectateurs pourront tirer des leçons. Voir Comment répondre pour plus d'informations. Aussi, «sous-sol»?
Heretic Monkey
0

Permettez-moi de commencer en disant que je ne recommande pas d'utiliser la méthode que je suis sur le point de suggérer. Il est beaucoup mieux à l' événement l' utilisation du développement conduit et se lient uniquement les événements aux éléments que vous êtes intéressé à savoir si la souris ou non plus avec mouseover, mouseout, mouseenter, mouseleave, etc.

Si vous DEVEZ absolument avoir la capacité de savoir sur quel élément se trouve la souris, vous devez écrire une fonction qui lie l' mouseoverévénement à tout dans le DOM, puis stocker tout l'élément actuel dans une variable.

Vous pourriez donc quelque chose comme ça:

window.which_element_is_the_mouse_on = (function() {

    var currentElement;

    $("body *").on('mouseover', function(e) {
        if(e.target === e.currentTarget) {
            currentElement = this;
        }
    });

    return function() {
        console.log(currentElement);    
    }
}());

Fondamentalement, j'ai créé une fonction immédiate qui définit l'événement sur tous les éléments et stocke l'élément actuel dans la fermeture pour minimiser votre empreinte.

Voici une démo fonctionnelle qui appelle window.which_element_is_the_mouse_onchaque seconde et enregistre l'élément sur lequel la souris se trouve actuellement sur la console.

http://jsfiddle.net/LWFpJ/1/

Philip Walton
la source
0

Ancienne question mais voici une solution pour ceux qui ont encore du mal. Vous souhaitez ajouter un mouseoverévénement sur l'élément «parent» du ou des éléments enfants que vous souhaitez détecter. Le code ci-dessous vous montre comment s'y prendre.

const wrapper = document.getElementById('wrapper') //parent element
const position = document.getElementById("displaySelection")

wrapper.addEventListener('mousemove', function(e) {
  let elementPointed = document.elementFromPoint(e.clientX, e.clientY)

  console.log(elementPointed)
});

DÉMO SUR CODEPEN

UZOR
la source