Tentukan elemen mana penunjuk mouse berada di atas dalam Javascript

110

Saya menginginkan fungsi yang memberi tahu saya elemen mana kursor mouse berakhir.

Jadi, misalnya, jika mouse pengguna berada di atas area teks ini (dengan id wmd-input), pemanggilan window.which_element_is_the_mouse_on()akan secara fungsional setara dengan$("#wmd-input")

Tom Lehman
sumber

Jawaban:

148

DEMO

Ada fungsi document.elementFromPointyang sangat keren yang disebut berfungsi seperti apa.

Yang kita butuhkan adalah menemukan x dan y coord dari mouse dan kemudian memanggilnya menggunakan nilai tersebut:

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

document.elementFromPoint

jQuery objek acara

qwertymk.dll
sumber
1
@TikhonJelvis: Nah dari sini saya melihat itu didukung di IE dan firefox. Jika Anda mendapatkan keduanya, Anda biasanya mendapatkan semuanya. MSDN MDN
qwertymk
1
Hebat. Apakah ada cara untuk mendapatkan coord mouse TANPA menonton acara? (Mungkin saya tidak berasumsi). Jika ini tidak memungkinkan, maka sayangnya saya tidak berpikir metode ini lebih baik dari event.targetatau apa pun
Tom Lehman
1
@HoraceLoeb Ini tidak mungkin untuk mendapatkan coord mouse tanpa menangkap acara. lihat pertanyaan SO ini untuk penjelasan lebih lanjut
Logan Besecker
2
Itu cara yang aneh untuk melakukannya. Jika Anda menangkap sebuah acara, mengapa tidak menggunakan saja event.target?
pmrotule
3
Jawaban tidak menjelaskan apa eventitu, dan bagaimana hal itu terjadi
vsync
64

Di browser yang lebih baru, Anda dapat melakukan hal berikut:

document.querySelectorAll( ":hover" );

Itu akan memberi Anda NodeList item yang mouse saat ini berada dalam urutan dokumen. Elemen terakhir di NodeList adalah yang paling spesifik, setiap elemen sebelumnya haruslah orang tua, kakek nenek, dan seterusnya.

dherman
sumber
2
Ini sepertinya tidak berhasil saat saya menyeret beberapa <li>saat di atas <li>elemen lainnya .
Seiyria
2
Saya membuat biola dengan $(':hover')tetapi pada dasarnya sama: jsfiddle.net/pmrotule/2pks4tf6
pmrotule
3
(function(){ var q = document.querySelectorAll(":hover"); return q[q.length-1]; })()
pengguna
3
Saya merasa kinerja ini mengerikan .. memanggil ini mousemovemungkin merusak kinerja
vsync
49

Meskipun pertanyaan berikut mungkin tidak benar-benar menjawab pertanyaan, karena ini adalah hasil pertama dari googling (googler mungkin tidak menanyakan pertanyaan yang persis sama :), harap ini akan memberikan masukan tambahan.

Sebenarnya ada dua pendekatan berbeda untuk mendapatkan daftar semua elemen yang mouse saat ini berakhir (untuk browser yang lebih baru, mungkin):

Pendekatan "struktural" - Pohon DOM menaik

Seperti dalam jawaban dherman, seseorang dapat menelepon

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

Namun, ini mengasumsikan bahwa hanya anak-anak yang akan menghamparkan leluhur mereka, yang biasanya terjadi, tetapi tidak benar secara umum, terutama ketika berhadapan dengan SVG di mana elemen di cabang berbeda dari pohon DOM mungkin saling tumpang tindih.

Pendekatan "visual" - Berdasarkan tumpang tindih "visual"

Metode ini digunakan document.elementFromPoint(x, y)untuk menemukan elemen paling atas, menyembunyikannya untuk sementara (karena kami segera memulihkannya dalam konteks yang sama, browser tidak akan benar-benar merendernya), lalu lanjutkan untuk menemukan elemen teratas kedua ... Terlihat sedikit hacky, tetapi ia mengembalikan apa yang Anda harapkan saat ada, misalnya, elemen saudara dalam pohon saling menutupi satu sama lain. Silakan temukan posting ini untuk lebih jelasnya,

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

Cobalah keduanya, dan periksa hasil yang berbeda.

herrlich10
sumber
Ini sangat membantu saya. Terima kasih @ herrlich10. Anehnya, kode Anda juga menangani kasus dengan elemen turunan bersarang.
Vikram Deshmukh
Ini sangat berguna. Persis apa yang saya cari. Seperti yang Anda katakan, querySelectorAll tidak berfungsi di setiap skenario.
noobsharp
4
@ herrlich10 Sepertinya ini adalah polyfill yang layak untuk developer.mozilla.org/en-US/docs/Web/API/Document/… . Jika API itu ada di browserSet yang Anda dukung, saya rasa Anda bisa menggunakannya.
dherman
Terima kasih untuk ini - berfungsi cukup banyak seperti yang diharapkan (meskipun tidak ada elemen. Kebalikan untuk compat dengan getElementsFromPoint), tetapi jauh lebih lambat (18-20ms per panggilan dalam pengujian saya di chrome) yang membuatnya sulit untuk digunakan dalam skenario yang saya alami di pikiran (menemukan target penurunan selama tarik dalam kasus saat menggunakan pendekatan berbasis peristiwa yang lebih mendasar tidak dapat dilakukan).
jsdw
1
lihat Document.elementsFromPoint(x, y) stackoverflow.com/a/31805883/1059828
Karl Adler
21

elementFromPoint()hanya mendapatkan elemen pertama di pohon DOM. Ini sebagian besar TIDAK cukup untuk kebutuhan pengembang. Untuk mendapatkan lebih dari satu elemen pada misalnya posisi penunjuk mouse saat ini, inilah fungsi yang Anda butuhkan:

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

Ini mengembalikan larik semua objek elemen di bawah titik yang diberikan. Cukup berikan nilai X dan Y mouse ke fungsi ini.

Info lebih lanjut di sini: https://developer.mozilla.org/en-US/docs/Web/API/document/elementsFromPoint

Untuk browser yang sangat lama yang tidak didukung, Anda dapat menggunakan jawaban ini sebagai fallback.

Karl Adler
sumber
3
Ini didukung dengan baik sekarang di 2018.
Boy
6

Arahkan kursor ke gelembung acara, sehingga Anda dapat meletakkan satu pendengar di badan dan menunggu sampai mereka menggelembung, lalu ambil event.targetatau event.srcElement:

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

<body onmouseover="doSomething(getTarget(event));">
RobG
sumber
Sementara saya sendiri menggunakan event handler universal, ini akan menjadi sumber daya yang lebih mahal daripada document.elementFromPoint(x, y).
Yohanes
6

Kode berikut akan membantu Anda mendapatkan elemen penunjuk mouse. Elemen yang dihasilkan akan ditampilkan di konsol.

document.addEventListener('mousemove', function(e) {
    console.log(document.elementFromPoint(e.pageX, e.pageY)); 
})
saikumar
sumber
1
Ini membutuhkan kursor untuk bergerak. Sedekat mungkin, bukan itu yang ditanyakan di sini.
Carles Alcolea
Tidak berfungsi jika halaman di-scroll. Gunakan e.clientXdan e.clientYsebagai gantinya (diuji di Firefox 59).
youen
5

Anda dapat melihat target mouseoveracara pada beberapa leluhur yang sesuai:

var currentElement = null;

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

Berikut demo nya.

Ry-
sumber
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. -->
Celupkan M
sumber
3
Saya minta maaf atas perlakuan buruk Anda terhadap pertanyaan Anda (sekarang dihapus). Secara pribadi saya lebih suka pertanyaan itu tidak dihapus. Sementara itu dalam perjalanan untuk ditutup (secara tidak adil, menurut saya), saya berencana memilih untuk membukanya kembali. Namun, mengingat jumlah suara negatif, saya mengerti jika Anda memilih untuk tetap menghapusnya.
halfer
3

DEMO: D Gerakkan mouse Anda di jendela cuplikan: D

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

Zibri
sumber
1

Target mousemoveacara DOM adalah elemen DOM paling atas di bawah kursor saat mouse bergerak:

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

Ini mirip dengan solusi @Philip Walton, tetapi tidak memerlukan jQuery atau setInterval.

Max Heiber
sumber
1

Anda dapat menggunakan selektor ini untuk merusak objek dan kemudian memanipulasinya sebagai objek jquery. $(':hover').last();

Serge Gordeev
sumber
4
Selamat datang di Stack Overflow! Mohon tambahkan beberapa penjelasan mengapa kode ini membantu OP. Ini akan membantu memberikan jawaban yang dapat dipelajari pemirsa di masa mendatang. Lihat Bagaimana Menjawab untuk informasi lebih lanjut. Juga, "merusak"?
Heretic Monkey
0

Izinkan saya memulai dengan mengatakan bahwa saya tidak merekomendasikan penggunaan metode yang akan saya sarankan. Ini jauh lebih baik untuk penggunaan event driven pengembangan dan mengikat peristiwa hanya untuk elemen Anda tertarik untuk mengetahui apakah atau tidak mouse di atas dengan mouseover, mouseout, mouseenter, mouseleave, dll

Jika Anda benar-benar HARUS memiliki kemampuan untuk mengetahui elemen mana yang dilewati mouse, Anda perlu menulis fungsi yang mengikat mouseoveracara ke semua yang ada di DOM, lalu menyimpan apa pun elemen saat ini di beberapa variabel.

Anda bisa melakukan sesuatu seperti ini:

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

Pada dasarnya, saya telah membuat fungsi langsung yang menyetel acara di semua elemen dan menyimpan elemen saat ini di dalam closure untuk meminimalkan footprint Anda.

Berikut adalah demo yang berfungsi window.which_element_is_the_mouse_on setiap detik dan mencatat elemen apa yang mouse saat ini ke konsol.

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

Philip Walton
sumber
0

Pertanyaan lama tapi inilah solusi bagi mereka yang mungkin masih berjuang. Anda ingin menambahkan mouseoveracara pada elemen 'induk' dari elemen anak yang ingin Anda deteksi. Kode di bawah ini menunjukkan kepada Anda bagaimana melakukannya.

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

UZOR
sumber