Determina su quale elemento si trova il puntatore del mouse in Javascript


109

Voglio una funzione che mi dica su quale elemento si trova il cursore del mouse.

Quindi, ad esempio, se il mouse dell'utente si trova su questa textarea (con id wmd-input), la chiamata window.which_element_is_the_mouse_on()sarà funzionalmente equivalente a$("#wmd-input")

Risposte:


147

DEMO

C'è una funzione davvero interessante chiamata document.elementFromPointche fa quello che sembra.

Ciò di cui abbiamo bisogno è trovare le coordinate xey del mouse e quindi chiamarlo usando quei valori:

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

document.elementFromPoint

Oggetto evento jQuery


1
@TikhonJelvis: Beh da qui vedo che è supportato su IE e Firefox. Se prendi quei due di solito li ottieni tutti. MSDN MDN
qwertymk

1
Eccezionale. C'è un modo per ottenere le coordinate del mouse SENZA cogliere un evento? (Probabilmente non presumo). Se questo non è possibile, sfortunatamente non penso che questo metodo sia migliore di event.targeto altro
Tom Lehman

1
@HoraceLoeb Non è possibile ottenere le coordinate del mouse senza rilevare un evento. vedere questa domanda SO per ulteriori spiegazioni
Logan Besecker

2
È un modo strano per farlo. Se prendi un evento, perché non usarlo event.target?
pmrotule

3
La risposta non spiega cosa eventsia e come sia stato
vsync

64

Nei browser più recenti, puoi eseguire le seguenti operazioni:

document.querySelectorAll( ":hover" );

Questo ti darà un NodeList di elementi su cui si trova attualmente il mouse nell'ordine del documento. L'ultimo elemento in NodeList è il più specifico, ciascuno precedente dovrebbe essere un genitore, un nonno e così via.


2
Questo non sembrava funzionare mentre trascinavo un <li>po 'di tempo sopra altri <li>elementi.
Seiyria

2
Ho creato un violino con $(':hover')ma è fondamentalmente la stessa cosa: jsfiddle.net/pmrotule/2pks4tf6
pmrotule

3
(function(){ var q = document.querySelectorAll(":hover"); return q[q.length-1]; })()
utente

3
Ho la sensazione che la performance di questo sia orribile .. chiamare questo mousemovepotrebbe danneggiare la performance
vsync

49

Sebbene quanto segue potrebbe non rispondere effettivamente alla domanda, poiché questo è il primo risultato del googling (il googler potrebbe non porre esattamente la stessa domanda :), spero che fornisca qualche input extra.

In realtà esistono due diversi approcci per ottenere un elenco di tutti gli elementi su cui si trova attualmente il mouse (forse per i browser più recenti):

L'approccio "strutturale" - Albero DOM ascendente

Come nella risposta di Dherman, si può chiamare

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

Tuttavia, questo presuppone che solo i bambini si sovrapporranno ai loro antenati, il che di solito è il caso, ma non è vero in generale, specialmente quando si ha a che fare con SVG dove elementi in diversi rami dell'albero DOM possono sovrapporsi l'un l'altro.

L'approccio "visivo" - Basato sulla sovrapposizione "visiva"

Questo metodo utilizza document.elementFromPoint(x, y)per trovare l'elemento più in alto, nasconderlo temporaneamente (poiché lo recuperiamo immediatamente nello stesso contesto, il browser non lo renderà effettivamente), quindi prosegui per trovare il secondo elemento più in alto ... Sembra un po 'hacky, ma restituisce ciò che ci si aspetta quando, ad esempio, elementi fratelli in un albero si occludono a vicenda. Si prega di trovare questo post per maggiori dettagli,

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

Prova entrambi e controlla i loro diversi rendimenti.


Questo mi ha aiutato molto. Grazie @ herrlich10. Sorprendentemente, il tuo codice gestisce il caso anche con elementi figli nidificati.
Vikram Deshmukh

Questo è estremamente utile. Esattamente quello che stavo cercando. Come hai detto, querySelectorAll non funziona in tutti gli scenari.
noobsharp

4
@ herrlich10 Questo sembra un discreto polyfill per developer.mozilla.org/en-US/docs/Web/API/Document/… . Se quell'API esiste nel tuo browserSet supportato, penso che potresti usarlo.
dherman

Grazie per questo - funziona più o meno come previsto (anche se nessun elements.reverse per compatibilità con getElementsFromPoint), ma è leggermente più lento (18-20 ms per chiamata nei miei test in Chrome) che lo rende difficile da usare nello scenario che avevo in mente (non è possibile trovare obiettivi di rilascio durante un trascinamento in un caso quando si utilizza un approccio basato sugli eventi più semplice).
jsdw

1
vedi Document.elementsFromPoint(x, y) stackoverflow.com/a/31805883/1059828
Karl Adler

21

elementFromPoint()ottiene solo il primo elemento nell'albero DOM. Questo per lo più NON è sufficiente per le esigenze degli sviluppatori. Per ottenere più di un elemento, ad esempio, la posizione corrente del puntatore del mouse questa è la funzione che ti serve:

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

Restituisce un array di tutti gli oggetti elemento sotto il punto specificato. Basta passare i valori X e Y del mouse a questa funzione.

Maggiori informazioni qui: https://developer.mozilla.org/en-US/docs/Web/API/document/elementsFromPoint

Per browser molto vecchi che non sono supportati, puoi utilizzare questa risposta come riserva.


3
È ben supportato ora nel 2018.
Ragazzo

6

Bolla degli eventi al passaggio del mouse, quindi puoi mettere un singolo ascoltatore sul corpo e attendere che si gonfino, quindi prendi il event.targeto event.srcElement:

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

<body onmouseover="doSomething(getTarget(event));">

Anche se io stesso utilizzo gestori di eventi universali, questo sarebbe più costoso in termini di risorse rispetto a document.elementFromPoint(x, y).
John

6

Il codice seguente ti aiuterà a ottenere l'elemento del puntatore del mouse. Gli elementi risultanti verranno visualizzati nella console.

document.addEventListener('mousemove', function(e) {
    console.log(document.elementFromPoint(e.pageX, e.pageY)); 
})

1
Ciò richiede che il cursore si muova. Per quanto vicino potrebbe essere, non è quello che viene chiesto qui.
Carles Alcolea

Non funziona se si scorre la pagina. Usa e.clientXe e.clientYinvece (testato su Firefox 59).
Youen

5

Puoi guardare l'obiettivo mouseoverdell'evento su un antenato adatto:

var currentElement = null;

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

Ecco una demo.


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. -->

3
Mi scuso per il modo in cui sei stato trattato sulla tua domanda (ora cancellata). Personalmente preferirei che la domanda non venisse cancellata. Mentre stava per essere chiuso (ingiustamente, a mio avviso), avevo intenzione di votare per riaprirlo. Tuttavia, dato il numero di voti negativi, capisco se scegli di mantenerlo cancellato.
halfer

3

DEMO: D Muovi il mouse nella finestra dello snippet: D

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


1

L'obiettivo mousemovedell'evento DOM è l'elemento DOM più in alto sotto il cursore quando il mouse si sposta:

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

È simile alla soluzione di @Philip Walton, ma non richiede jQuery o setInterval.


1

Puoi usare questo selettore per undermouse oggetto e poi manipolarlo come oggetto jquery. $(':hover').last();


4
Benvenuto in Stack Overflow! Si prega di aggiungere qualche spiegazione del motivo per cui questo codice aiuta l'OP. Ciò contribuirà a fornire una risposta da cui i futuri spettatori potranno imparare. Vedere Come rispondere per ulteriori informazioni. Inoltre, "undermouse"?
Scimmia eretica

0

Vorrei iniziare dicendo che non consiglio di utilizzare il metodo che sto per suggerire. E 'molto meglio utilizzare event-driven di sviluppo e si legano gli eventi solo per gli elementi che ti interessa sapere se il mouse si trova sopra con mouseover, mouseout, mouseenter, mouseleave, etc.

Se DEVI assolutamente avere la capacità di sapere su quale elemento si trova il mouse, dovresti scrivere una funzione che associ l' mouseoverevento a tutto nel DOM e quindi memorizzare qualunque sia l'elemento corrente in una variabile.

Potresti quindi qualcosa del genere:

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

Fondamentalmente, ho creato una funzione immediata che imposta l'evento su tutti gli elementi e memorizza l'elemento corrente all'interno della chiusura per ridurre al minimo il tuo footprint.

Ecco una demo funzionante che chiama window.which_element_is_the_mouse_onogni secondo e registra sulla console l'elemento su cui si trova attualmente il mouse.

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


0

Vecchia domanda ma ecco una soluzione per coloro che potrebbero ancora essere in difficoltà. Desideri aggiungere un mouseoverevento all'elemento "genitore" degli elementi secondari che desideri rilevare. Il codice seguente mostra come procedere.

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 SU CODEPEN

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.