可以使用以下技术确定鼠标光标下方的元素(即最顶端的元素):
mousemove
事件。目标是
event.target
或 document.elementFromPoint(event.clientX, event.clientY)
。在不移动鼠标的情况下滚动时,这不起作用。然后,鼠标在技术上不动;因此,不会发生任何鼠标事件。
不幸的是,在收听scroll
事件时,上述两种技术都不再适用。 event.target
将是滚动的任何元素(或document
)。此外,鼠标光标位置未在event
对象上公开。
如this answer to “Determine which element the mouse pointer is on top of in Javascript”中所述,一种可能的解决方案是通过CSS :hover
伪类查询悬停元素。
document.addEventListener('scroll', () => {
const hoverTarget = document.querySelector('.element:hover');
if (hoverTarget) {
hover(hoverTarget);
}
});
然而,这是不可用的,因为它非常低效且不准确。 scroll
事件是快速触发的事件之一,在执行任何代价高昂的事情时(例如查询DOM)需要放慢速度。
此外,滚动时,悬停元素落后于。您可以在任何具有大量链接的网站上观察到这一点:将鼠标悬停在其中一个上并滚动到另一个链接而不移动鼠标。它只在几毫秒后更新。
有什么办法,这可以很好地实现吗?基本上,我想要mouseenter
的倒数:我不想知道鼠标何时进入和元素,我想知道一个元素何时与鼠标相交(例如当鼠标没有移动但是元素[即滚动时] )。
答案 0 :(得分:2)
解决此问题的一种方法是将鼠标光标位置与mousemove
事件一起存储,并在scroll
事件中使用document.elementFromPoint(x, y)
来确定应该悬停的元素。
请记住,由于scroll
事件以如此高的频率被触发,因此效率仍然非常低。事件处理程序应该去抖以将函数的执行限制为每个延迟一次。 David Walsh在JavaScript Debounce Function中解释了如何执行此操作。
let hoveredElement;
let mouseX = 0, mouseY = 0;
document.addEventListener('DOMContentLoaded', () => {
document.addEventListener('mousemove', event => {
mouseX = event.clientX;
mouseY = event.clientY;
hover(event.target);
});
document.addEventListener('scroll', () => {
const hoverTarget = document.elementFromPoint(mouseX, mouseY);
if (hoverTarget) {
hover(hoverTarget);
}
});
});
function hover(targetElement) {
// If the target and stored element are the same, return early
// because setting it again is unnecessary.
if (hoveredElement === targetElement) {
return;
}
// On first run, `hoveredElement` is undefined.
if (hoveredElement) {
hoveredElement.classList.remove('hover');
}
hoveredElement = targetElement;
hoveredElement.classList.add('hover');
}
.element {
height: 200px;
border: 2px solid tomato;
}
.element.hover {
background-color: lavender;
}
<div class="container">
<div class="element element-1">1</div>
<div class="element element-2">2</div>
<div class="element element-3">3</div>
<div class="element element-4">4</div>
<div class="element element-5">5</div>
</div>
目前,解决方案将在移动鼠标和滚动时将鼠标悬停在鼠标下方。您可能更适合将mousemove
侦听器附加到一组特定元素,然后始终悬停event.currentTarget
(即事件侦听器附加到的元素)。对于scroll
部分,您可以使用hoverTarget.closest
在DOM树中查找合适的元素。