Bestimmen Sie, auf welchem ​​Element sich der Mauszeiger in Javascript befindet

109

Ich möchte eine Funktion, die mir sagt, über welchem ​​Element sich der Mauszeiger befindet.

Befindet sich beispielsweise die Maus des Benutzers über diesem Textbereich (mit ID wmd-input), entspricht der Aufruf window.which_element_is_the_mouse_on()funktional dem$("#wmd-input")

Tom Lehman
quelle

Antworten:

147

DEMO

Es gibt eine wirklich coole Funktion, document.elementFromPointdie macht, wie es sich anhört.

Was wir brauchen, ist, die x- und y-Koordinaten der Maus zu finden und sie dann mit diesen Werten aufzurufen:

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

document.elementFromPoint

jQuery-Ereignisobjekt

qwertymk
quelle
1
@TikhonJelvis: Nun, von hier aus sehe ich, dass es von IE und Firefox unterstützt wird. Wenn Sie diese beiden bekommen, bekommen Sie normalerweise alle. MSDN MDN
qwertymk
1
Genial. Gibt es eine Möglichkeit, die Koordinaten der Maus zu erhalten, ohne ein Ereignis zu erfassen? (Vermutlich nicht, nehme ich an). Wenn dies nicht möglich ist, dann denke ich leider nicht, dass diese Methode besser ist als event.targetoder was auch immer
Tom Lehman
1
@HoraceLoeb Es ist nicht möglich, die Mauskoordinaten zu erhalten, ohne ein Ereignis zu erfassen. siehe diese SO-Frage für weitere Erklärung
Logan Besecker
2
Das ist eine seltsame Art, es zu tun. Wenn Sie eine Veranstaltung abfangen, warum nicht einfach verwenden event.target?
pmrotule
3
Die Antwort erklärt nicht, was eventist und wie es dazu kam
vsync
64

In neueren Browsern können Sie Folgendes tun:

document.querySelectorAll( ":hover" );

Dadurch erhalten Sie eine NodeList mit Elementen, über die sich die Maus derzeit in der Dokumentreihenfolge befindet. Das letzte Element in der NodeList ist das spezifischste. Jedes vorhergehende Element sollte ein Elternteil, ein Großelternteil usw. sein.

Dherman
quelle
2
Dies schien nicht zu funktionieren, während ich eine <li>Weile über andere <li>Elemente zog.
Seiyria
2
Ich habe eine Geige mit erstellt, $(':hover')aber es ist im Grunde das gleiche: jsfiddle.net/pmrotule/2pks4tf6
pmrotule
3
(function(){ var q = document.querySelectorAll(":hover"); return q[q.length-1]; })()
Benutzer
3
Ich habe das Gefühl, dass die Leistung davon schrecklich ist. mousemove
Wenn Sie
49

Obwohl das Folgende die Frage möglicherweise nicht wirklich beantwortet, da dies das erste Ergebnis des Googelns ist (der Googler stellt möglicherweise nicht genau die gleiche Frage :), hoffe ich, dass es zusätzliche Informationen liefert.

Es gibt zwei verschiedene Ansätze, um eine Liste aller Elemente zu erhalten, über die sich die Maus gerade befindet (für neuere Browser möglicherweise):

Der "strukturelle" Ansatz - Aufsteigender DOM-Baum

Wie in Dhermans Antwort kann man anrufen

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

Dies setzt jedoch voraus, dass nur Kinder ihre Vorfahren überlagern, was normalerweise der Fall ist, aber im Allgemeinen nicht zutrifft, insbesondere wenn es sich um SVG handelt, bei dem sich Elemente in verschiedenen Zweigen des DOM-Baums möglicherweise überlappen.

Der "visuelle" Ansatz - Basierend auf "visuellen" Überlappungen

Diese Methode verwendet document.elementFromPoint(x, y), um das oberste Element zu finden, es vorübergehend auszublenden (da wir es sofort im selben Kontext wiederherstellen, wird es vom Browser nicht wirklich gerendert) und dann das zweitoberste Element zu finden ... Sieht ein wenig hackig aus, aber Es gibt zurück, was Sie erwarten, wenn sich beispielsweise Geschwisterelemente in einem Baum befinden, die sich gegenseitig verschließen. Bitte finden Sie diesen Beitrag für weitere Details,

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;
}

Probieren Sie beide aus und überprüfen Sie die unterschiedlichen Renditen.

herrlich10
quelle
Das hat mir sehr geholfen. Danke @ herrlich10. Überraschenderweise behandelt Ihr Code den Fall auch mit verschachtelten untergeordneten Elementen.
Vikram Deshmukh
Dies ist äußerst nützlich. Genau das, wonach ich gesucht habe. Wie Sie sagten, funktioniert querySelectorAll nicht in jedem Szenario.
Noobsharp
4
@ herrlich10 Dies scheint eine anständige Polyfüllung für developer.mozilla.org/en-US/docs/Web/API/Document/… zu sein . Wenn diese API in Ihrem unterstützten Browser-Set vorhanden ist, können Sie sie meiner Meinung nach verwenden.
Dherman
Vielen Dank dafür - funktioniert so ziemlich wie erwartet (obwohl keine elements.reverse für die Kompatibilität mit getElementsFromPoint), aber es ist viel langsamer (18-20 ms pro Aufruf in meinen Tests in Chrome), was es schwierig macht, es in dem Szenario zu verwenden, in dem ich es hatte mind (das Finden von Drop-Zielen während eines Ziehens in einem Fall, in dem ein grundlegenderer ereignisgesteuerter Ansatz verwendet wird, ist nicht möglich).
jsdw
1
siehe Document.elementsFromPoint(x, y) stackoverflow.com/a/31805883/1059828
Karl Adler
21

elementFromPoint()Ruft nur das erste Element im DOM-Baum ab. Dies ist meistens NICHT genug für Entwickleranforderungen. Um mehr als ein Element an der aktuellen Mauszeigerposition zu erhalten, benötigen Sie folgende Funktion:

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

Dies gibt ein Array aller Elementobjekte unter dem angegebenen Punkt zurück. Übergeben Sie einfach die X- und Y-Werte der Maus an diese Funktion.

Weitere Informationen finden Sie hier: https://developer.mozilla.org/en-US/docs/Web/API/document/elementsFromPoint

Bei sehr alten Browsern, die nicht unterstützt werden, können Sie diese Antwort als Fallback verwenden.

Karl Adler
quelle
3
Es wird jetzt im Jahr 2018 gut unterstützt.
Boy
6

Mouseover-Ereignisse sprudeln, sodass Sie einen einzelnen Hörer auf den Körper setzen und warten können, bis sie aufblähen, und dann das event.targetoder greifen event.srcElement:

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

<body onmouseover="doSomething(getTarget(event));">
RobG
quelle
Während ich selbst universelle Ereignishandler verwende, wäre dies ressourcenintensiver als document.elementFromPoint(x, y).
John
6

Der folgende Code hilft Ihnen dabei, das Element des Mauszeigers abzurufen. Die resultierenden Elemente werden in der Konsole angezeigt.

document.addEventListener('mousemove', function(e) {
    console.log(document.elementFromPoint(e.pageX, e.pageY)); 
})
Saikumar
quelle
1
Dazu muss sich der Cursor bewegen. So nah es auch sein mag, es ist nicht das, was hier gefragt wird.
Carles Alcolea
Funktioniert nicht, wenn die Seite gescrollt wird. Verwenden Sie stattdessen e.clientXund e.clientY(getestet in Firefox 59).
Youen
5

Sie können das Ziel des mouseoverEreignisses anhand eines geeigneten Vorfahren anzeigen:

var currentElement = null;

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

Hier ist eine Demo.

Ry-
quelle
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.
quelle
3
Ich entschuldige mich für die schlechte Art und Weise, wie Sie in Ihrer (jetzt gelöschten) Frage behandelt wurden. Persönlich würde ich es vorziehen, wenn die Frage nicht beantwortet würde. Während es auf dem Weg war, geschlossen zu werden (meiner Ansicht nach zu Unrecht), plante ich eine Abstimmung, um es wieder zu öffnen. Angesichts der Anzahl der Abstimmungen verstehe ich jedoch, ob Sie die Löschung beibehalten möchten.
Halfer
3

DEMO: D Bewegen Sie Ihre Maus im Snippet-Fenster: D.

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

Zibri
quelle
1

Das Ziel des mousemoveDOM-Ereignisses ist das oberste DOM-Element unter dem Cursor, wenn sich die Maus bewegt:

(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;
        }
    });
})();

Dies ähnelt der Lösung von @Philip Walton, erfordert jedoch weder jQuery noch ein setInterval.

Max Heiber
quelle
1

Mit diesem Selektor können Sie ein Objekt unterbieten und es dann als Abfrageobjekt bearbeiten. $(':hover').last();

Serge Gordeev
quelle
4
Willkommen bei Stack Overflow! Bitte fügen Sie eine Erklärung hinzu, warum dieser Code dem OP hilft. Dies wird dazu beitragen, eine Antwort zu geben, von der zukünftige Zuschauer lernen können. Siehe Wie Antwort für weitere Informationen. Auch "Unterwäsche"?
Heretic Monkey
0

Lassen Sie mich zunächst sagen, dass ich die von mir vorgeschlagene Methode nicht empfehle. Es ist viel besser zu Einsatz ereignisgesteuerter Entwicklung und binden Ereignisse nur auf die Elemente , die Sie interessiert sind zu wissen , ob die Maus mit ist vorbei mouseover, mouseout, mouseenter,mouseleave etc.

Wenn Sie unbedingt wissen müssen, über welchem ​​Element sich die Maus befindet, müssen Sie eine Funktion schreiben, die das mouseoverEreignis an alles im DOM bindet , und dann das aktuelle Element in einer Variablen speichern.

Sie könnten so etwas wie das:

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);    
    }
}());

Grundsätzlich habe ich eine Sofortfunktion erstellt, die das Ereignis für alle Elemente festlegt und das aktuelle Element im Abschluss speichert, um Ihren Platzbedarf zu minimieren.

Hier ist eine funktionierende Demo, die window.which_element_is_the_mouse_onjede Sekunde aufruft und protokolliert, über welches Element sich die Maus gerade in der Konsole befindet.

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

Philip Walton
quelle
0

Alte Frage, aber hier ist eine Lösung für diejenigen, die möglicherweise noch Probleme haben. Sie möchten mouseoverdem übergeordneten Element der untergeordneten Elemente, die erkannt werden sollen , ein Ereignis hinzufügen . Der folgende Code zeigt Ihnen, wie Sie vorgehen müssen.

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)
});

DEMO ON CODEPEN

UZOR
quelle