简体   繁体   English

滚动时将元素悬停在鼠标光标下方

[英]Hover the element below the mouse cursor when scrolling

One can determine the element below the mouse cursor (ie the top-most hovered element) with the following techniques: 可以使用以下技术确定鼠标光标下方的元素(即最顶部的悬停元素):

  • Listen for the mousemove event. 听取mousemove事件。 The target is 目标是
    • event.target or event.target
    • document.elementFromPoint(event.clientX, event.clientY) . document.elementFromPoint(event.clientX, event.clientY)

This does not work when scrolling while not moving the mouse . 在不移动鼠标的情况下滚动时,这不起作用。 Then, the mouse technically doesn't move; 然后,鼠标在技术上不动; thus, no mouse event will fire. 因此,不会发生任何鼠标事件。

Unfortunately, both techniques from above are no longer applicable when listening for the scroll event. 不幸的是,在收听scroll事件时,上述两种技术都不再适用。 event.target will be whichever element is scrolled (or document ). event.target将是滚动(或document )的任何元素。 Also, the mouse cursor position is not exposed on the event object. 此外,鼠标光标位置未在event对象上公开。

As described in this answer to “Determine which element the mouse pointer is on top of in Javascript” , one possible solution is querying the hovered element via the CSS :hover pseudo-class. 正如在“确定鼠标指针位于Javascript顶部的哪个元素”的回答中所述 ,一种可能的解决方案是通过CSS :hover伪类查询悬停元素。

document.addEventListener('scroll', () => {
  const hoverTarget = document.querySelector('.element:hover');
  if (hoverTarget) {
    hover(hoverTarget);
  }
});

However, this is not usable because it is very inefficient and inaccurate. 但是,这是不可用的,因为它非常低效且不准确。 The scroll event is one of the rapidly firing events and needs to be slowed down when performing anything mildly costly (eg querying the DOM). scroll事件是快速触发事件之一,并且在执行任何稍微昂贵的任务时(例如查询DOM)需要减慢速度。

Also, the hovered element lags behind when scrolling. 此外,滚动时悬停元素滞后 You can observe this on any kind of website with a lot of links: Hover over one of them and scroll to another link without moving the mouse. 您可以在任何具有大量链接的网站上观察到这一点:将鼠标悬停在其中一个上并滚动到另一个链接而不移动鼠标。 It updates only after a few milliseconds. 它仅在几毫秒后更新。

Is there any way, this can be implemented nicely and efficient? 有什么办法,这可以很好地实现吗? Basically, I want the inverse of mouseenter : Instead of knowing when the mouse enters and element, I want to know when an element intersects with the mouse (eg when the mouse is not moved but the element [ie when scrolling]). 基本上,我想要mouseenter的逆:我不想知道鼠标何时进入和元素,我想知道元素何时与鼠标相交(例如,当鼠标未被移动而是元素[即滚动时])。

One approach of tackling this is storing the mouse cursor location with the mousemove event and in the scroll event use document.elementFromPoint(x, y) to figure out the element that should be hovered. 解决此问题的一种方法是使用mousemove事件存储鼠标光标位置,并在scroll事件中使用document.elementFromPoint(x, y)来计算应该悬停的元素。

Keep in mind that this is still pretty inefficient due to the scroll event being fired with such a high frequency. 请记住,由于scroll事件以如此高的频率触发,这仍然是非常低效的。 The event handler should be debounced to limit execution of the function to once per delay. 应该去抖动事件处理程序以将函数的执行限制为每个延迟一次。 David Walsh explains how to do this in JavaScript Debounce Function . 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> 

Currently, the solution will hover the top-most element under the mouse both when moving the mouse and when scrolling. 目前,该解决方案将在移动鼠标和滚动时将鼠标悬停在鼠标下方。 It might be more suitable for your needs to attach the mousemove listener to a set of specific elements and then always hover event.currentTarget (ie the element the event listener was attached to). 它可能更适合您的需要将mousemove侦听器附加到一组特定元素,然后始终悬停event.currentTarget (即事件侦听器附加到的元素)。 As for the scroll part, you can use hoverTarget.closest to find the suitable element up in the DOM tree. 对于scroll部分,您可以使用hoverTarget.closest在DOM树中查找合适的元素。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM