JavaScript'te fare işaretçisinin hangi öğenin üstünde olduğunu belirleyin


111

Fare imlecinin hangi öğenin üzerinde olduğunu söyleyen bir işlev istiyorum.

Bu nedenle, örneğin, kullanıcının faresi bu metin alanının üzerindeyse (kimlikli wmd-input), arama window.which_element_is_the_mouse_on()işlevi ile eşdeğer olacaktır $("#wmd-input").

Yanıtlar:


148

DEMO

document.elementFromPointKulağa benzeyen şeyi yapan gerçekten harika bir işlev var .

İhtiyacımız olan şey, farenin x ve y koordinatlarını bulmak ve sonra onu bu değerleri kullanarak çağırmaktır:

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

document.elementFromPoint

jQuery olay nesnesi


1
@TikhonJelvis: Buradan IE ve firefox'ta desteklendiğini görüyorum. Bu ikisini alırsanız, genellikle hepsini alırsınız. MSDN MDN
qwertymk

1
Harika. Bir olayı yakalamadan farenin koordinatlarını almanın bir yolu var mı? (Muhtemelen varsaymıyorum). Bu mümkün değilse, maalesef bu yöntemin ondan daha iyi olduğunu event.targetya da her neyse olduğunu düşünmüyorum
Tom Lehman

1
@HoraceLoeb Bir olay yakalamadan fare koordinatlarını almak mümkün değildir. daha fazla açıklama için bu SO sorusuna bakın
Logan Besecker

2
Bunu yapmanın tuhaf bir yolu. Bir etkinliği yakalarsanız, neden sadece kullanmıyorsunuz event.target?
pmrotule

3
Cevap ne eventolduğunu ve nasıl ortaya çıktığını açıklamıyor
vsync

64

Daha yeni tarayıcılarda şunları yapabilirsiniz:

document.querySelectorAll( ":hover" );

Bu size farenin şu anda belge sırasına göre üzerinde olduğu öğelerin bir Düğüm Listesini verecektir. DüğümListesindeki son öğe en spesifik olandır, önceki her bir öğe bir üst, büyükbaba vb. Olmalıdır.


2
Bu, bir <li>süre diğer <li>öğelerin üzerine sürüklerken işe yaramadı .
Seiyria

2
Bir keman oluşturdum $(':hover')ama temelde aynı şey: jsfiddle.net/pmrotule/2pks4tf6
pmrotule

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

3
Bunun performansının korkunç olduğunu hissediyorum .. bunu söylemek performansa mousemovezarar verebilir
vsync

49

Aşağıdakiler soruyu gerçekten yanıtlamasa da, bu, googling'in ilk sonucu olduğundan (Google çalışanı tam olarak aynı soruyu sormayabilir :), umarım fazladan girdi sağlar.

Farenin şu anda üzerinde olduğu tüm öğelerin bir listesini almak için aslında iki farklı yaklaşım vardır (belki daha yeni tarayıcılar için):

"Yapısal" yaklaşım - Artan DOM ağacı

Olduğu gibi dherman cevabı , tek çağırabilirsiniz

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

Bununla birlikte, bu, yalnızca çocukların atalarının üst üste geleceğini varsayar, bu genellikle böyledir, ancak genel olarak doğru değildir, özellikle DOM ağacının farklı dallarındaki öğelerin birbiriyle çakışabileceği SVG ile uğraşırken.

"Görsel" yaklaşım - "Görsel" örtüşmeye dayalı

Bu yöntem document.elementFromPoint(x, y), en üstteki öğeyi bulmak, geçici olarak gizlemek için kullanır (aynı bağlamda hemen kurtardığımız için, tarayıcı bunu gerçekten oluşturmayacaktır), ardından en üstteki ikinci öğeyi bulmaya devam eder ... Biraz karmaşık görünüyor, ancak örneğin, bir ağaçta birbirini tıkayan kardeş öğeler olduğunda beklediğiniz şeyi döndürür. Daha fazla ayrıntı için lütfen bu gönderiyi bulun ,

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

İkisini de deneyin ve farklı getirilerini kontrol edin.


Bu bana çok yardımcı oldu. @ Herrlich10 teşekkürler. Şaşırtıcı bir şekilde, kodunuz durumu iç içe geçmiş alt öğelerle de ele alır.
Vikram Deshmukh

Bu son derece kullanışlıdır. Tam olarak aradığım şey. Dediğiniz gibi querySelectorAll her senaryoda çalışmıyor.
noobsharp

4
@ herrlich10 Bu, developer.mozilla.org/en-US/docs/Web/API/Document/… için iyi bir çoklu dolgu gibi görünüyor . Bu API, desteklenen browserSet'inizde mevcutsa, bunu kullanabileceğinizi düşünüyorum.
dherman

Bunun için teşekkürler - hemen hemen açıklandığı kadar çalışıyor (getElementsFromPoint ile uyumluluk için hiçbir element.reverse olsa da), ancak çok daha yavaştır (kromdaki testimde arama başına 18-20ms), bu da senaryoda kullanmamı zorlaştırıyor mind (daha temel olay odaklı bir yaklaşım kullanıldığında bir durumda sürükleme sırasında düşme hedefleri bulmak mümkün değildir).
jsdw

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

21

elementFromPoint()DOM ağacındaki yalnızca ilk öğeyi alır. Bu çoğunlukla geliştiricilerin ihtiyaçları için yeterli değildir . Örneğin mevcut fare işaretçisi konumunda birden fazla öğe elde etmek için ihtiyacınız olan işlev budur:

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

Bu, verilen nokta altındaki tüm eleman nesnelerinin bir dizisini döndürür. Fare X ve Y değerlerini bu işleve aktarmanız yeterlidir.

Daha fazla bilgi burada: DocumentOrShadowRoot.elementsFromPoint ()

Desteklenmeyen çok eski tarayıcılar için, bu yanıtı bir geri dönüş olarak kullanabilirsiniz .


3
Şimdi 2018'de iyi destekleniyor.
Boy

6

Olay balonunun üzerine fareyle gelin, böylece vücuda tek bir dinleyici yerleştirebilir ve bunların kabarmasını bekleyebilir, ardından event.targetveya event.srcElement:

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

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

Ben evrensel olay işleyicileri kullansam da, bu kaynak açısından daha pahalı olacaktır document.elementFromPoint(x, y).
John

6

Aşağıdaki kod, fare işaretçisinin öğesini elde etmenize yardımcı olacaktır. Ortaya çıkan öğeler konsolda görüntülenecektir.

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

1
Bu, imlecin hareket etmesini gerektirir. Olabildiğince yakın, burada istenen şey bu değil.
Carles Alcolea

Sayfa kaydırılırsa çalışmaz. Onun yerine e.clientXve e.clientYkullanın (Firefox 59'da test edilmiştir).
2018

5

mouseoverBazı uygun atalarda olayın hedefine bakabilirsiniz :

var currentElement = null;

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

İşte bir 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
(Artık silinmiş) sorunuza karşı muamele gördüğünüz kötü tavır için özür dilerim. Şahsen ben sorunun silinmemiş olmasını tercih ederim. Kapanma yolundayken (bana göre haksız bir şekilde), onu yeniden açmak için oy vermeyi planlıyordum. Ancak, olumsuz oyların sayısı göz önüne alındığında, onu silinmiş olarak tutup tutmamanızı anlıyorum.
halfer

3

Demo: D

Farenizi pasaj penceresinde hareket ettirin: D

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


1

mousemoveDOM olayının hedefi , fare hareket ettiğinde imlecin altındaki en üstteki DOM öğesidir:

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

Bu, @Philip Walton'ın çözümüne benzer, ancak jQuery veya setInterval gerektirmez.


1

Bu seçiciyi nesnenin altını oymak ve ardından onu bir jQuery nesnesi olarak değiştirmek için kullanabilirsiniz:

$(':hover').last();

4
Stack Overflow'a hoş geldiniz! Lütfen bu kodun neden OP'ye yardımcı olduğuna dair bazı açıklamalar ekleyin. Bu, gelecekteki izleyicilerin öğrenebileceği bir yanıt sağlamaya yardımcı olacaktır. Daha fazla bilgi için Nasıl Cevaplanır bölümüne bakın . Ayrıca "baltalamak" mı?
Heretic Maymun

Nedir "undermouse nesneye" ? "Farenin altındaki nesneye" mi demek istiyorsun ? Veya başka bir şey?
Peter Mortensen

0

İşte hala mücadele ediyor olabilecekler için bir çözüm. mouseoverAlgılanmasını istediğiniz alt öğe (ler) in 'ana' öğesine bir olay eklemek istiyorsunuz. Aşağıdaki kod, bunu nasıl yapacağınızı gösterir.

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

CodePen'de Demo


0

Önermek üzere olduğum yöntemi kullanmanızı önermediğimi söyleyerek başlayayım. Sadece fare ile üzerine olup olmadığını bilmeden ilgilenen konum öğelere kullanım olay güdümlü geliştirme ve bağlama olaylara çok daha iyi mouseover, mouseout, mouseenter, mouseleave, vb

Kesinlikle Eğer gerekir fare üzerinde olan eleman bilmek yeteneği var, bağlar bir işlevi iletişim kurmanız gerekir mouseoversonra DOM her şeye olay ve mevcut eleman bazı değişkende ne olursa olsun saklayın.

Bunun gibi bir şey yapabilirsin:

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

Temel olarak, etkinliği tüm öğeler üzerinde ayarlayan ve ayak izinizi en aza indirgemek için mevcut öğeyi kapanışta depolayan anında bir işlev oluşturdum.

İşte window.which_element_is_the_mouse_onher saniye çağıran ve farenin şu anda hangi öğenin konsolda olduğunu kaydeden çalışan bir demo .

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.