Xác định phần tử mà con trỏ chuột ở trên cùng trong Javascript


109

Tôi muốn một hàm cho tôi biết phần tử nào con trỏ chuột kết thúc.

Vì vậy, ví dụ: nếu chuột của người dùng ở trên vùng văn bản này (có id wmd-input), việc gọi window.which_element_is_the_mouse_on()sẽ có chức năng tương đương với$("#wmd-input")

Câu trả lời:


147

BẢN GIỚI THIỆU

Có một chức năng thực sự thú vị được gọi là document.elementFromPointnó hoạt động như thế nào.

Những gì chúng ta cần là tìm các coords x và y của chuột và sau đó gọi nó bằng các giá trị đó:

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

document.elementFromPoint

đối tượng sự kiện jQuery


1
@TikhonJelvis: Từ đây tôi thấy nó được hỗ trợ trên IE và firefox. Nếu bạn nhận được hai cái đó, bạn thường nhận được tất cả. MSDN MDN
qwertymk

1
Tuyệt vời. Có cách nào để có được những con chuột mà không cần bắt một sự kiện? (Chắc không phải tôi cho là vậy). Nếu đây là không thể, sau đó tiếc là tôi không nghĩ rằng phương pháp này là bất kỳ tốt hơn event.targethoặc bất cứ điều gì
Tom Lehman

1
@HoraceLoeb Không thể lấy dây chuột mà không bắt một sự kiện. thấy câu hỏi này SO cho giải thích thêm
Logan Besecker

2
Đó là một cách kỳ lạ để làm điều đó. Nếu bạn nắm bắt một sự kiện, tại sao không chỉ sử dụng event.target?
pmrotule

3
Câu trả lời không giải thích nó eventlà gì và nó ra sao
vsync

64

Trong các trình duyệt mới hơn, bạn có thể làm như sau:

document.querySelectorAll( ":hover" );

Điều đó sẽ cung cấp cho bạn Danh sách NodeList của các mục mà chuột hiện đang lướt qua theo thứ tự tài liệu. Phần tử cuối cùng trong NodeList là phần tử cụ thể nhất, mỗi phần tử đứng trước phải là cha mẹ, ông bà, v.v.


2
Điều này dường như không hoạt động khi tôi đang kéo một <li>lúc trên các <li>phần tử khác .
Seiyria,

2
Tôi tạo ra một fiddle với $(':hover')nhưng đó là về cơ bản cùng một điều: jsfiddle.net/pmrotule/2pks4tf6
pmrotule

3
(function(){ var q = document.querySelectorAll(":hover"); return q[q.length-1]; })()
người dùng

3
Tôi có cảm giác hiệu suất của điều này thật kinh khủng .. gọi điều này mousemovecó thể ảnh hưởng đến hiệu suất
vsync

49

Mặc dù phần sau có thể không thực sự trả lời câu hỏi, vì đây là kết quả đầu tiên của googling (trình duyệt có thể không hỏi chính xác câu hỏi giống nhau :), hy vọng nó sẽ cung cấp thêm một số thông tin đầu vào.

Trên thực tế, có hai cách tiếp cận khác nhau để có được danh sách tất cả các yếu tố mà con chuột hiện đang sử dụng (có lẽ đối với các trình duyệt mới hơn):

Phương pháp "cấu trúc" - Cây DOM tăng dần

Như trong câu trả lời của dherman, người ta có thể gọi

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

Tuy nhiên, điều này giả định rằng chỉ con cái mới phủ lên tổ tiên của chúng, điều này thường xảy ra, nhưng không đúng nói chung, đặc biệt là khi xử lý SVG trong đó phần tử trong các nhánh khác nhau của cây DOM có thể chồng lên nhau.

Phương pháp tiếp cận "trực quan" - Dựa trên chồng chéo "trực quan"

Phương pháp này sử dụng document.elementFromPoint(x, y)để tìm phần tử trên cùng, tạm thời ẩn nó (vì chúng tôi khôi phục nó ngay lập tức trong cùng ngữ cảnh, trình duyệt sẽ không thực sự hiển thị điều này), sau đó tiếp tục tìm phần tử trên cùng thứ hai ... Trông hơi hacky, nhưng nó trả về những gì bạn mong đợi khi có, ví dụ: các phần tử anh chị em trong một cây che khuất nhau. Vui lòng tìm bài đăng này để biết thêm chi tiết,

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

Hãy thử cả hai và kiểm tra lợi nhuận khác nhau của chúng.


Điều này đã giúp tôi rất nhiều. Cảm ơn @ herrlich10. Đáng ngạc nhiên là mã của bạn cũng xử lý trường hợp với các phần tử con lồng nhau.
Vikram Deshmukh

Điều này là cực kỳ hữu ích. Chính xác những gì tôi đang tìm kiếm. Như bạn đã nói, querySelectorAll không hoạt động trong mọi trường hợp.
noobsharp

4
@ herrlich10 Đây có vẻ như là một polyfill phù hợp cho developer.mozilla.org/en-US/docs/Web/API/Document/… . Nếu API đó tồn tại trong Bộ trình duyệt được hỗ trợ của bạn, tôi nghĩ bạn có thể sử dụng API đó.
dherman

Cảm ơn vì điều này - hoạt động khá nhiều như được thực thi (mặc dù không có phần tử nào. Ngược để tương thích với getElementsFromPoint), nhưng nó chậm hơn (18-20ms mỗi cuộc gọi trong thử nghiệm của tôi trong chrome) khiến khó sử dụng trong trường hợp tôi đã gặp phải (không thể tìm thấy mục tiêu thả trong khi kéo trong trường hợp sử dụng cách tiếp cận hướng sự kiện cơ bản hơn).
jsdw

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

21

elementFromPoint()chỉ nhận phần tử đầu tiên trong cây DOM. Điều này hầu như KHÔNG đủ cho nhu cầu của các nhà phát triển. Để có được nhiều hơn một phần tử tại vị trí con trỏ chuột hiện tại, đây là chức năng bạn cần:

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

Điều này trả về một mảng tất cả các đối tượng phần tử dưới điểm đã cho. Chỉ cần chuyển các giá trị X và Y của chuột vào hàm này.

Thông tin thêm tại đây: https://developer.mozilla.org/en-US/docs/Web/API/document/elementsFromPoint

Đối với các trình duyệt rất cũ không được hỗ trợ, bạn có thể sử dụng câu trả lời này làm dự phòng.


3
Nó hiện được hỗ trợ tốt trong năm 2018.
Boy

6

Bong bóng sự kiện di chuột qua, vì vậy bạn có thể đặt một người nghe vào cơ thể và đợi họ bong bóng, sau đó lấy event.targethoặc event.srcElement:

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

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

Trong khi bản thân tôi sử dụng các trình xử lý sự kiện phổ quát, điều này sẽ là nguồn tài nguyên đắt tiền hơn document.elementFromPoint(x, y).
John

6

Đoạn mã sau đây sẽ giúp bạn lấy phần tử của con trỏ chuột. Các phần tử kết quả sẽ hiển thị trong bảng điều khiển.

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

1
Điều này yêu cầu con trỏ di chuyển. Gần như có thể, nó không phải là những gì đang được hỏi ở đây.
Carles Alcolea

Không hoạt động nếu trang được cuộn. Sử dụng e.clientXe.clientYthay thế (thử nghiệm trên Firefox 59).
youen

5

Bạn có thể xem mục tiêu của mouseoversự kiện trên một số tổ chức phù hợp:

var currentElement = null;

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

Đây là một bản 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
Tôi xin lỗi vì cách đối xử kém cỏi đối với câu hỏi của bạn (hiện đã bị xóa). Cá nhân tôi muốn câu hỏi không bị xóa. Trong khi nó đang trên đường bị đóng cửa (theo quan điểm của tôi là không công bằng), tôi đã có kế hoạch bỏ phiếu để mở lại nó. Tuy nhiên, với số phiếu phản đối, tôi hiểu nếu bạn chọn giữ nó bị xóa.
halfer

3

DEMO: D Di chuyển chuột của bạn trong cửa sổ đoạn mã: D

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


1

Mục tiêu của mousemovesự kiện DOM là phần tử DOM cao nhất dưới con trỏ khi chuột di chuyển:

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

Điều này tương tự như giải pháp của @Philip Walton, nhưng không yêu cầu jQuery hoặc setInterval.


1

Bạn có thể sử dụng bộ chọn này để khai thác đối tượng và hơn là thao tác đối tượng đó như đối tượng jquery. $(':hover').last();


4
Chào mừng bạn đến với Stack Overflow! Vui lòng thêm một số giải thích về lý do tại sao mã này giúp OP. Điều này sẽ giúp cung cấp câu trả lời mà người xem trong tương lai có thể học hỏi. Xem Cách trả lời để biết thêm thông tin. Ngoài ra, "undermouse"?
Heretic Monkey

0

Hãy để tôi bắt đầu bằng cách nói rằng tôi không khuyên bạn nên sử dụng phương pháp mà tôi sắp đề xuất. Đó là tốt hơn để sử dụng sự kiện thúc đẩy phát triển và ràng buộc sự kiện duy nhất để các yếu tố bạn đang quan tâm đến việc biết hay không chuột đã qua với mouseover, mouseout, mouseenter, mouseleavevv

Nếu bạn hoàn toàn PHẢI có khả năng biết con chuột đang ở phần tử nào, bạn cần viết một hàm liên kết mouseoversự kiện với mọi thứ trong DOM, rồi lưu trữ bất kỳ phần tử hiện tại nào trong một số biến.

Bạn có thể như thế này:

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

Về cơ bản, tôi đã tạo một hàm ngay lập tức đặt sự kiện trên tất cả các phần tử và lưu trữ phần tử hiện tại trong phần đóng để giảm thiểu dấu chân của bạn.

Đây là bản demo hoạt động gọi window.which_element_is_the_mouse_onmỗi giây và ghi lại phần tử mà con chuột hiện đang truy cập vào bảng điều khiển.

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


0

Câu hỏi cũ nhưng là một giải pháp cho những ai có thể vẫn đang gặp khó khăn. Bạn muốn thêm mouseoversự kiện vào phần tử 'cha' của (các) phần tử con mà bạn muốn phát hiện. Đoạn mã dưới đây cho bạn biết cách thực hiện nó.

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 TRÊN CODEPEN

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.