如何在没有事件的情况下获取鼠标位置(不移动鼠标)?

Posted

技术标签:

【中文标题】如何在没有事件的情况下获取鼠标位置(不移动鼠标)?【英文标题】:How to get the mouse position without events (without moving the mouse)? 【发布时间】:2011-02-05 18:20:03 【问题描述】:

是否可以在页面加载后在没有任何鼠标移动事件(不移动鼠标)的情况下使用 javascript 获取鼠标位置?

【问题讨论】:

mousemove 事件没有问题。只是在某些情况下,用户不会移动鼠标。谢谢你的回答。 Norbert Tamas,@SuperNova 的回答(直到今年才添加)表明 mouseenter 可以正常工作,因为它在页面加载时触发(如果鼠标在视口中)。它在 2010 年不是这样工作的,还是只是没有人想过尝试它? @CrescentFresh 在某些情况下(例如用户脚本),您不想通过添加许多 mousemove 事件来减慢浏览器的速度。 鼠标悬停在 FF 中可能,但在 IE 和 Chrome 中不可用。 或者,在游戏中,您的相机在游戏世界中移动,而角色正在注视鼠标(典型的自上而下的射击游戏风格),但如果用户不移动鼠标,它会以周围为中心如果您只依赖mousemove,则在您四处移动时会出现错误的点。不过,这没什么大不了的,我们只是存储指针的“世界”坐标,然后让人们查询。 【参考方案1】:

真正的答案:不,不可能。

好的,我刚刚想到了一个办法。用覆盖整个文档的 div 覆盖您的页面。在其中,创建(比如说)2,000 x 2,000 <a> 元素(这样:hover 伪类将在 IE 6 中工作,请参阅),每个元素大小为 1 个像素。为那些更改属性的<a> 元素创建一个CSS :hover 规则(比如font-family)。在您的负载处理程序中,循环浏览 400 万个 <a> 元素中的每一个,检查 currentStyle / getComputedStyle() 直到找到带有悬停字体的那个。从此元素外推以获取文档中的坐标。

注意不要这样做

【讨论】:

哈哈 - 在某些时候你应该谷歌一下,看看你是否能弄清楚有多少人实际实现了这个 实际上,它是可以实现的,无需太多的 CPU 负载(我认为。我还没有测试过)。在 dom 准备好使用 javascript 构建 元素时,将鼠标放在一个位置,然后删除所有 元素。在鼠标鼠标上,您应该具有其他功能来获取鼠标位置。无论如何,这很有趣。 也许这可以通过二分搜索来实现?循环制作一对覆盖给定矩形的<a>元素(我想使用大小<img>元素的绝对定位),每次都缩小矩形。是的,这很荒谬,但是在第一次鼠标移动之前无法获取此信息。 ***.com/a/8543879/27024 表示在鼠标第一次移动之前悬停不会触发。这挫败了这个计划。 @DariusBacon:链接的答案似乎不正确:jsbin.com/utocax/3。所以是的,这种方法在某些情况下可能是实用的。【参考方案2】:

您可以做的是为光标的xy 坐标创建变量,在鼠标移动时更新它们,并在间隔上调用一个函数来对存储的位置执行您需要的操作。

当然,这样做的缺点是至少需要鼠标进行一次初始移动才能使其工作。只要光标至少更新一次位置,无论它是否再次移动,我们都能找到它的位置。

var cursor_x = -1;
var cursor_y = -1;
document.onmousemove = function(event)

 cursor_x = event.pageX;
 cursor_y = event.pageY;

setInterval(check_cursor, 1000);
function check_cursor()console.log('Cursor at: '+cursor_x+', '+cursor_y);

上述代码每秒更新一次,并显示光标所在位置的消息。我希望这会有所帮助。

【讨论】:

你读过这篇文章的主题吗? OP 询问如何在不使用事件的情况下获取鼠标坐标。然而,您的帖子建议使用 onmousemove 事件。 @jake 虽然 OP 专门要求使用非事件方法,但这个答案有利于其他来这里寻找答案和可能的解决方法的人。此外,我会在主题内部分考虑这个答案,因为据我所知,这是在任何给定时间获取光标位置的最佳方法,而无需直接使用事件。话虽如此,答案的措辞可能更接近于陈述事实并提供一种避免在 cmets 中吹毛求疵的方法。 @Pichan 这对我没有好处,因为我一直在寻找一种方法来在任何事件发生之前填充那些 cursorX/Y 变量。 很少有用户不会触发鼠标事件 小心,保留 mousemove 监听器的成本可能很高。我建议在间隔中重新创建侦听器并在获得坐标后销毁侦听器。【参考方案3】:
var x = 0;
var y = 0;

document.addEventListener('mousemove', onMouseMove, false)

function onMouseMove(e)
    x = e.clientX;
    y = e.clientY;


function getMouseX() 
    return x;


function getMouseY() 
    return y;

【讨论】:

这还不需要用户移动鼠标吗? 是的,但只是第一步。然后当它移动时,我们已经知道 px X Y【参考方案4】:

我设想您可能有一个带有计时器的父页面,并且在一定时间或任务完成后,您将用户转发到一个新页面。现在您需要光标位置,因为它们正在等待,它们不一定会触摸鼠标。因此,使用标准事件在父页面上跟踪鼠标,并在 get 或 post 变量中将最后一个值传递给新页面。

您可以在父页面上使用 JHarding 的代码,以便在全局变量中始终提供最新位置:

var cursorX;
var cursorY;
document.onmousemove = function(e)
    cursorX = e.pageX;
    cursorY = e.pageY;

这不会帮助通过您的父页面以外的方式导航到此页面的用户。

【讨论】:

【参考方案5】:

我实现了一个横向/纵向的搜索,(先做一个横向排列的全竖线链接的div,然后再做一个纵向排列的全横线链接的div,简单看看哪个有hover状态)就像Tim Down的想法上面,它工作得非常快。遗憾的是,在 KDE 上的 Chrome 32 上不起作用。

jsfiddle.net/5XzeE/4/

【讨论】:

显然这些技巧不再起作用,除非用户明确地移动鼠标。 :(【参考方案6】:

Edit 2020:不再工作了。浏览器供应商似乎已经修补了这个问题。因为大多数浏览器都依赖于 Chromium,所以它可能是它的核心。

旧答案: 您还可以挂钩 mouseenter (此事件在页面重新加载后触发,当鼠标光标在页面内时)。扩展 Corrupted 的代码应该可以解决问题:

var x = null;
var y = null;
    
document.addEventListener('mousemove', onMouseUpdate, false);
document.addEventListener('mouseenter', onMouseUpdate, false);
    
function onMouseUpdate(e) 
  x = e.pageX;
  y = e.pageY;
  console.log(x, y);


function getMouseX() 
  return x;


function getMouseY() 
  return y;

您还可以在 mouseleave-event 上将 x 和 y 设置为 null。因此,您可以使用光标检查用户是否在您的页面上。

【讨论】:

这似乎是这里唯一真正有用的答案,这似乎很奇怪。实际上(在最新的 Firefox、Chrome 和 IE11 中)mouseenter 在页面加载时触发并提供正确的坐标。在过去几年中,该领域的浏览器行为是否发生了变化? 事实上“mouseenter”似乎并没有增加任何价值。我在 Chrome 和 IE 中使用以下 jsfiddle 进行了测试,直到您将鼠标放在内部文档(结果面板)上,它们才会显示坐标:jsfiddle.net/xkpd784o/1 @Proton:在页面完全加载之前,将鼠标移动到结果面板的结果面板区域并且不要移动。加载后页面立即知道鼠标的位置。无需鼠标移动。因此,当页面加载并且鼠标位于文档区域内时,也会触发 mouseenter。也就是说,OP最初想要什么。没有其他人提供这个答案。 一个可能有用的附加功能是为mouseleave 事件添加一个函数,将xy 设置回null'undefined' chrome 68,使用上面的jsfiddel,在第一次鼠标移动而不是加载时会出现警报,即使在页面完成加载之前鼠标移动到渲染区域也是如此。【参考方案7】:

您可以尝试类似于 Tim Down 建议的方法 - 但不是为屏幕上的每个像素创建元素,而是仅创建 2-4 个元素(框),并动态更改它们的位置、宽度、高度以划分可能屏幕上的位置递归2-4,从而快速找到鼠标的真实位置。

例如 - 第一个元素占据屏幕的左右半部分,然后是上半部分和下半部分。到目前为止,我们已经知道鼠标位于屏幕的哪个四分之一,能够重复 - 发现这个空间的哪个四分之一......

【讨论】:

【参考方案8】:

如果您渲染 2,000 x 2,000 <a> 元素,@Tim Down 的答案是不高效的:

好的,我刚刚想到了一个办法。用 div 覆盖您的页面 涵盖整个文档。在里面,创建(比如说)2,000 x 2,000 元素(这样 :hover 伪类将在 IE 6 中工作,请参阅), 每 1 个像素大小。为这些元素创建一个 CSS :hover 规则 这会改变一个属性(比如说字体系列)。在您的负载处理程序中, 循环遍历 400 万个元素中的每一个,检查 currentStyle / getComputedStyle() 直到找到带有 悬停字体。从此元素外推以获得坐标 在文档中。

注意不要这样做。

但您不必一次渲染 400 万个元素,而是使用二进制搜索。只需使用 4 个 <a> 元素即可:

第 1 步:将整个屏幕视为起始搜索区域 第 2 步:将搜索区域拆分为 2 x 2 = 4 个矩形 <a> 元素 第 3 步:使用 getComputedStyle() 函数确定鼠标悬停在哪个矩形中 第 4 步:将搜索区域缩小到该矩形,然后从第 2 步开始重复。

考虑到您的屏幕宽度不超过 2048 像素,您最多需要重复这些步骤 11 次。

因此您将生成最多 11 x 4 = 44 个<a> 元素。

如果您不需要将鼠标位置精确到一个像素,但说 10px 精度是可以的。您最多会重复这些步骤 8 次,因此您最多需要绘制 8 x 4 = 32 <a> 元素。

同时生成然后销毁<a> 元素也不会执行,因为 DOM 通常很慢。相反,您可以重复使用最初的 4 个<a> 元素,并在循环执行步骤时调整它们的topleftwidthheight

现在,创建 4 个<a> 也是一种矫枉过正。相反,您可以在每个矩形中测试getComputedStyle() 时重复使用相同的<a> 元素。因此,不要将搜索区域拆分为 2 x 2 <a> 元素,只需使用 topleft 样式属性移动单个 <a> 元素即可。

因此,您只需将单个 <a> 元素更改其 widthheight 最多 11 次,并将其 topleft 最多更改 44 次,您将获得准确的鼠标位置。

【讨论】:

【参考方案9】:

您不必移动鼠标来获取光标的位置。除了 mousemove 之外的事件也会报告该位置。下面以 点击事件 为例:

document.body.addEventListener('click',function(e)

    console.log("cursor-location: " + e.clientX + ',' + e.clientY);
);

【讨论】:

【参考方案10】:

最简单的解决方案,但不是 100% 准确

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

结果:top: 148, left: 62.5 结果取决于最近的元素大小并在用户切换标签时返回undefined

【讨论】:

对我来说,无论如何它都会返回undefined。你能详细说明如何使用它吗? 当光标没有悬停在任何元素上(或者当浏览器失去焦点时)它会返回undefined。如果您从控制台进行测试,您可能需要设置时间间隔.. 谢谢。 setTimeout 工作。我使用的是 jsfiddle,你是对的,它从来没有遇到悬停事件,因为它每次点击播放时都会重绘 DOM。我建议为其他人添加此提示。 我不想要准确的鼠标位置,但我只想知道鼠标在没有事件对象的情况下是极右还是极左,所以你的解决方案适用于我的情况..谢谢【参考方案11】:

参考@SuperNova's answer,这是一种使用 ES6 类的方法,可以在回调中保持this 的上下文正确:

class Mouse 
  constructor() 
    this.x = 0;
    this.y = 0;
    this.callbacks = 
      mouseenter: [],
      mousemove: [],
    ;
  

  get xPos() 
    return this.x;
  

  get yPos() 
    return this.y;
  

  get position() 
    return `$this.x,$this.y`;
  

  addListener(type, callback) 
    document.addEventListener(type, this); // Pass `this` as the second arg to keep the context correct
    this.callbacks[type].push(callback);
  

  // `handleEvent` is part of the browser's `EventListener` API.
  // https://developer.mozilla.org/en-US/docs/Web/API/EventListener/handleEvent
  handleEvent(event) 
    const isMousemove = event.type === 'mousemove';
    const isMouseenter = event.type === 'mouseenter';

    if (isMousemove || isMouseenter) 
      this.x = event.pageX;
      this.y = event.pageY;
    

    this.callbacks[event.type].forEach((callback) => 
      callback();
    );
  


const mouse = new Mouse();

mouse.addListener('mouseenter', () => console.log('mouseenter', mouse.position));
mouse.addListener('mousemove', () => console.log('mousemove A', mouse.position));
mouse.addListener('mousemove', () => console.log('mousemove B', mouse.position));

【讨论】:

【参考方案12】:

这是我的解决方案。它导出您可以在任何地方使用的 window.currentMouseXwindow.currentMouseY 属性。它最初使用悬停元素(如果有)的位置,然后侦听鼠标移动以设置正确的值。

(function () 
    window.currentMouseX = 0;
    window.currentMouseY = 0;

    // Guess the initial mouse position approximately if possible:
    var hoveredElement = document.querySelectorAll(':hover');
    hoveredElement = hoveredElement[hoveredElement.length - 1]; // Get the most specific hovered element

    if (hoveredElement != null) 
        var rect = hoveredElement.getBoundingClientRect();
        // Set the values from hovered element's position
        window.currentMouseX = window.scrollX + rect.x;
        window.currentMouseY = window.scrollY + rect.y;
    

    // Listen for mouse movements to set the correct values
    window.addEventListener('mousemove', function (e) 
        window.currentMouseX = e.pageX;
        window.currentMouseY = e.pageY;
    , /*useCapture=*/true);
())

Composr CMS来源:https://github.com/ocproducts/composr/commit/a851c19f925be20bc16bfe016be42924989f262e#diff-b162dc9c35a97618a96748639ff41251R1202

【讨论】:

【参考方案13】:

我想我可能有一个合理的解决方案,不计算 div 和像素..lol

只需使用动画帧或函数的时间间隔。您仍然需要一次鼠标事件,尽管只是为了启动,但从技术上讲,您可以将其放置在您喜欢的任何位置。

基本上我们在没有鼠标移动的情况下一直跟踪一个虚拟 div。

// create a div(#mydiv) 1px by 1px set opacity to 0 & position:absolute;

下面是逻辑..

var x,y;


$('body').mousemove(function( e ) 

    var x = e.clientX - (window.innerWidth / 2);
    var y = e.clientY - (window.innerHeight / 2);
 


function looping ()

   /* track my div position 60 x 60 seconds!
      with out the mouse after initiation you can still track the dummy div.x & y
      mouse doesn't need to move.*/

   $('#mydiv').x = x;    // css transform x and y to follow 
   $('#mydiv)'.y = y;

   console.log(#mydiv.x etc)

   requestAnimationFrame( looping , frame speed here);
  

【讨论】:

【参考方案14】:

不是鼠标位置,但是,如果您正在寻找 当前光标位置(用于获取最后输入的字符等用例),那么下面的 sn-p 可以正常工作。 这将为您提供与文本内容相关的光标索引。

window.getSelection().getRangeAt(0).startOffset

【讨论】:

【参考方案15】:

是的,有可能。

如果你在文档中添加“mouseover”事件,它会立即触发并且你可以获得鼠标位置,当然如果鼠标指针在文档上。

   document.addEventListener('mouseover', setInitialMousePos, false);

   function setInitialMousePos( event ) 
       console.log( event.clientX, event.clientY);
       document.removeEventListener('mouseover', setInitialMousePos, false);
   

以前可以通过window.event 读取鼠标位置,但现在已弃用。

【讨论】:

以上是关于如何在没有事件的情况下获取鼠标位置(不移动鼠标)?的主要内容,如果未能解决你的问题,请参考以下文章

如何在按钮按下事件之外在 Silverlight 中获取鼠标按钮状态?

Qt 如何获取滚动窗体中鼠标点击的坐标

Java 鼠标获取 JTable 位置的移动

求qt在QGraphicsView中主动捕获鼠标位置的实现方法?

js获取鼠标当前的位置

鼠标拖拽事件