Визначте, на який елемент вказівник миші знаходиться зверху


110

Я хочу функцію, яка повідомляє мені, над яким елементом закінчується курсор миші.

Наприклад, якщо миша користувача перебуває над цією текстовою ділянкою (з id wmd-input), виклик window.which_element_is_the_mouse_on()буде функціонально еквівалентний$("#wmd-input")

Відповіді:


148

DEMO

Є по-справжньому класна функція, document.elementFromPointяка називається , як це звучить.

Що нам потрібно - це знайти координати миші x і y, а потім викликати їх за допомогою цих значень:

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

document.elementFromPoint

Об'єкт події jQuery


1
@TikhonJelvis: Ну звідси я бачу, що він підтримується в IE та firefox. Якщо ви отримаєте ці два, ви зазвичай отримуєте їх усі. MSDN MDN
qwertymk

1
Дивовижно. Чи є спосіб отримати координати миші БЕЗ лову події? (Мабуть, не припускаю). Якщо це неможливо, то, на жаль, я не вважаю, що цей метод є кращим event.targetабо будь-яким іншим
Том Леман,

1
@HoraceLoeb Неможливо отримати координати миші, не вловивши події. Дивіться це питання
ТА

2
Це дивний спосіб зробити це. Якщо ви ловите подію, чому б не просто скористатися event.target?
pmrotule

3
Відповідь не пояснює, що eventтаке, і як воно сталося
vsync

64

У нових веб-переглядачах ви можете зробити наступне:

document.querySelectorAll( ":hover" );

Це дасть вам NodeList елементів, над якими миша зараз закінчується в порядку документа. Останній елемент у NodeList є найбільш конкретним, кожен попередній повинен бути батьком, бабусею та дідусем тощо.


2
Це, здається, не спрацювало, коли я деякий <li>час перетягувався над іншими <li>елементами.
Seiyria

2
Я створив загадку,$(':hover') але це в основному те саме: jsfiddle.net/pmrotule/2pks4tf6
pmrotule

3
(function(){ var q = document.querySelectorAll(":hover"); return q[q.length-1]; })()
користувач

3
У мене є відчуття, що виконання цього моторошно ... дзвінок про це mousemoveможе зашкодити виставі
vsync

49

Хоча наступне може насправді не відповісти на питання, оскільки це перший результат googling (googler може не задавати точно таке саме питання :), сподіваємось, це дасть додатковий вклад.

Насправді існує два різних підходи, щоб отримати список усіх елементів, над якими миша наразі закінчена (можливо, для нових браузерів):

"Структурний" підхід - висхідне дерево DOM

Як і у відповіді дхермана, можна зателефонувати

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

Однак це передбачає, що лише діти будуть накладати своїх предків, що зазвичай буває, але взагалі не відповідає дійсності, особливо при роботі зі SVG, коли елементи в різних галузях дерева DOM можуть накладатися один на одного.

"Візуальний" підхід - заснований на "візуальному" перекритті

Цей метод використовує document.elementFromPoint(x, y)для пошуку самого верхнього елемента, тимчасово приховає його (оскільки ми відновимо його одразу в тому ж контексті, браузер насправді не рендерує це), потім перейдемо до пошуку другого верхнього елемента ... Виглядає трохи хакітно, але він повертає те, що ви очікуєте, коли на дереві є елементи братів і сестер, які окулюють один одного. Будь ласка, знайдіть цю публікацію для більш детальної інформації,

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

Спробуйте і те, і інше перевірити їх віддачу.


Це мені дуже допомогло. Дякую @ herrlich10. Дивно, але ваш код обробляє корпус і з вкладеними елементами дітей.
Вікрам Дешмух

Це надзвичайно корисно. Саме те, що я шукав. Як ви вже говорили, querySelectorAll працює не в кожному сценарії.
noobsharp

4
@ herrlich10 Це здається пристойним поліфайлом для developer.mozilla.org/en-US/docs/Web/API/Document/… . Якщо цей API існує у підтримуваному браузеріSet, я думаю, ви могли б це використовувати.
dherman

Дякую за це - працює майже як прискорений (хоча жодних елементів. Зворотній для співпраці з getElementsFromPoint), але це набагато повільніше (18-20 мс за дзвінок під час мого тестування в хромі), що робить його важким у використанні в сценарії, який я мав у розум (пошук цілей падіння під час перетягування у випадку, коли використання більш базового підходу, орієнтованого на події, неможливо).
jsdw

1
дивіться Document.elementsFromPoint(x, y) stackoverflow.com/a/31805883/1059828
Карл Адлер,

21

elementFromPoint()отримує лише перший елемент дерева DOM. В основному цього недостатньо для потреб розробників. Щоб отримати більше одного елемента, наприклад, поточне положення вказівника миші, це необхідна функція:

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

Це повертає масив усіх елементів елементів під заданою точкою. Просто передайте ці функції миші X та Y.

Більше інформації тут: https://developer.mozilla.org/en-US/docs/Web/API/document/elementsFromPoint

Для дуже старих веб-переглядачів, які не підтримуються, ви можете використовувати цю відповідь як резервну копію.


3
Це добре підтримується зараз у 2018 році.
Хлопчик

6

Пузир подій миші, тож ви можете покласти одного слухача на тіло і чекати, коли вони підняться, а потім схопити event.targetабо event.srcElement:

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

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

Хоча я сам використовую універсальні обробники подій, це було б дорожче, ніж розумний ресурс document.elementFromPoint(x, y).
Джон

6

Наступний код допоможе вам отримати елемент вказівника миші. Результати відображатимуться в консолі.

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

1
Це вимагає переміщення курсору. Наскільки це близько, це не те, про що тут питають.
Carles Alcolea

Не працює, якщо сторінка прокручується. Використовуйте e.clientXта e.clientYзамість цього (перевірено на Firefox 59).
youen

5

Ви можете подивитися ціль mouseoverподії на якогось підходящого предка:

var currentElement = null;

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

Ось демонстрація.


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
Прошу вибачення за поганий спосіб поводження з вами щодо вашого (тепер видаленого) запитання. Особисто я вважаю за краще, щоб питання не було вирішено. Хоча я був на шляху до закриття (несправедливо, на мій погляд), я планував голосувати за його повторне відкриття. Однак, враховуючи кількість протоколів, я розумію, якщо ви вирішите зберегти його видаленим.
половина

3

DEMO: D Перемістіть мишу у вікні фрагмента: D

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


1

Ціль mousemoveподії DOM - це самий верхній елемент DOM під курсором, коли миша рухається:

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

Це схоже на рішення @Philip Walton, але не вимагає jQuery або setInterval.


1

Ви можете використовувати цей селектор, щоб підмалювати об'єкт і чим маніпулювати ним як об'єктом jquery. $(':hover').last();


4
Ласкаво просимо до переповнення стека! Будь ласка, додайте пояснення, чому цей код допомагає ОП. Це допоможе надати відповідь, з якого майбутні глядачі можуть навчитися. Див. Як відповісти для отримання додаткової інформації. Також "підмишка"?
Єретична мавпа

0

Почніть з того, що я не рекомендую використовувати метод, про який я збираюся запропонувати. Це набагато краще використовувати подію з приводом розвитку і прив'язки подій тільки до елементів , які ви зацікавлені в знанні чи не миша знаходиться над з mouseover, mouseout, mouseenter, mouseleaveі т.д.

Якщо ви абсолютно ОБОВ'ЯЗКОВО маєте можливість знати, над яким елементом закінчується миша, вам потрібно буде написати функцію, яка прив'язує mouseoverподію до всього в DOM, а потім зберігати будь-який поточний елемент у певній змінній.

Ви можете так щось подібне:

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

В основному я створив безпосередню функцію, яка встановлює подію на всі елементи і зберігає поточний елемент в межах закриття, щоб мінімізувати ваш слід.

Ось робоча демонстрація, яка дзвонить window.which_element_is_the_mouse_onщосекунди і реєструє, який елемент миші зараз перейшов на консоль.

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


0

Старе питання, але ось рішення для тих, хто може все ще боротися. Ви хочете додати mouseoverподію до "батьківського" елемента дочірніх елементів, які ви хочете виявити. Наведений нижче код показує, як це зробити.

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.