如何获得没有事件的鼠标位置(不移动鼠标)?


286

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


61
mousemove事件没有问题。在某些情况下,用户不会移动鼠标。感谢您的回答。
诺伯特·塔马斯

2
@SuperNova的回答Norbert Tamas(直到今年才添加)表明mouseenter可以很好地工作,因为它会在页面加载时触发(如果鼠标在视口中)。在2010年这种方式行不通吗,还是只是没人想尝试一下?
彼得·汉森

@CrescentFresh在某些情况下(例如用户脚本),您不想通过添加许多mousemove事件来降低浏览器的速度。
托马什Zato -恢复莫妮卡

可以通过鼠标悬停在FF中,但在IE和Chrome中则不行。
伊拉德(Elad)2015年

或者,在游戏中,您的相机在游戏世界中移动,并且角色正在注视鼠标(典型的自上而下的射击风格),但是如果用户不移动鼠标,则当您移动鼠标时,它将围绕错误的点居中您仅依靠mousemove。但是,这没什么大不了的,我们只存储指针的“世界”坐标,让人们查询即可。
kamranicus

Answers:


336

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

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

注意:不要这样做


92
哈哈-在某个时候,您应该在Google周围搜索,看看是否可以算出实际上有多少人实现了这一点
Pointy 2010年

6
实际上,它可以实现而无需太多的CPU负载(我想。我尚未对其进行测试)。在dom上,准备好使用javascript构建<a>元素的方式,将鼠标移到然后删除所有<a>元素的位置。在mousemouse上,您应该具有其他功能来保持鼠标位置。无论如何,这很有趣。
machineaddict

21
也许可以通过二进制搜索将其变为现实?循环制作一对<a>覆盖给定矩形的<img>元素(我想使用尺寸元素的绝对定位),每次缩小矩形。是的,这很荒谬,但是在第一次移动鼠标之前无法获得此信息。
Darius Bacon

29
stackoverflow.com/a/8543879/27024表示,直到第一次移动鼠标时,鼠标才会触发。这挫败了这个计划。
Darius Bacon

4
@DariusBacon:这个链接的答案似乎不正确:jsbin.com/utocax/3。所以是的,这种方法在某些情况下可能是可行的。
Tim Down

121

编辑2020:不再起作用。浏览器供应商似乎对此进行了修补。因为大多数浏览器都依赖于铬,所以它可能是其核心。

旧的答案:您也可以挂钩mouseenter(当mousecursor位于页面内部时,页面重新加载后会触发此事件)。扩展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。因此,您可以使用光标检查用户是否在页面上。


11
这似乎是这里唯一真正有用的答案,这似乎很奇怪。实际上(在最新的Firefox,Chrome和IE11中),mouseenter会在页面加载时触发并提供正确的坐标。过去几年中,浏览器在该领域的行为是否发生了变化?
彼得·汉森

3
实际上,“ mouseenter”似乎并没有增加任何价值。我在Chrome和IE中对以下jsfiddle进行了测试,直到您将鼠标放在内部文档(结果面板)上时,它们才会显示座标
Mariano Desanze 2015年

1
@Proton:将鼠标移到结果面板上的resultpanel页面之前的区域已完全加载,并且不动。加载后,页面立即知道鼠标的位置。无需移动鼠标。因此,当页面已加载且鼠标位于文档区域内时,也会触发mouseenter。也就是说,OP最初想要的是什么。没有人提供这个答案。
SuperNova

1
一个可能有用的添加方法是为该mouseleave事件添加一个函数,该函数设置xy返回null'undefined'
rtpax

2
chrome 68(使用上面的jsfiddel),即使在页面完成加载之前将鼠标移动到呈现的区域,也会在第一次移动鼠标而不是加载时发生警报。
junvar

84

您所能做的就是为光标的xy坐标创建变量,每当鼠标移动时更新它们,并按一定间隔调用一个函数以根据存储的位置执行所需的操作。

当然,这样做的不利之处在于,至少需要鼠标的一次初始移动才能使其正常工作。只要光标至少更新一次其位置,我们就能够找到其位置,而不管其是否再次移动。

var cursorX;
var cursorY;
document.onmousemove = function(e){
    cursorX = e.pageX;
    cursorY = e.pageY;
}
setInterval(checkCursor, 1000);
function checkCursor(){
    alert("Cursor at: " + cursorX + ", " + cursorY);
}

前面的代码每秒更新一次,并显示一条有关光标位置的消息。我希望这有帮助。


18
您阅读了这篇文章的主题吗?OP询问如何在不使用事件的情况下获取鼠标坐标。但是您的帖子建议使用onmousemove事件。
2012年

53
@jake尽管OP明确要求使用非事件方法,但此答案使来这里寻求答案的其他人受益,也可能是解决方法。另外,我将在主题中部分考虑此答案,因为据我所知,这是在任何给定时间获取光标位置而不必直接使用事件的最佳方法。话虽如此,但答案的措辞可能更多是陈述事实,并提供了避免在评论中挑剔的方法。
jpeltoniemi 2013年

2
@Pichan这对我没有好处,因为我一直在寻找一种cursorX/Y在任何事件发生之前填充这些变量的方法。
polkovnikov.ph 2016年

极少数用户不会触发鼠标事件
SuperUberDuper '16

1
小心,保持鼠标移动的侦听器很昂贵。我建议您在间隔中重新创建侦听器,并在获得坐标后销毁侦听器。
KRB

10

您可以尝试类似Tim Down建议的方法-但不要在屏幕上为每个像素添加元素,而只需创建2-4个元素(框),然后动态更改其位置,宽度和高度即可划分屏幕上可能的位置按2-4递归,从而快速找到鼠标的真实位置。

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


9

如果渲染2,000 x 2,000个<a>元素,则@Tim Down的答案无效。

好的,我刚刚想到了一种方法。用覆盖整个文档的div覆盖页面。在其中,创建(说)2,000 x 2,000个元素(以便:hover伪类可在IE 6中运行,请参见),每个元素的大小为1像素。为那些更改属性的元素创建CSS:hover规则(比如说font-family)。在加载处理程序中,循环浏览这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>也是一个过大的杀伤力。相反,在每个矩形中<a>进行测试时,可以重复使用相同的一个元素getComputedStyle()。因此,与其将搜索区域划分为2 x 2个<a>元素,不如<a>通过使用topleft样式属性移动元素来重用单个元素。

因此,您只需要单个<a>元素更改其widthheight最大11次,然后更改其topleft最大44次,您将拥有精确的鼠标位置。


3

最简单的解决方案,但并非100%准确

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

结果:{top: 148, left: 62.5}
结果取决于最接近的元素大小,并undefined在用户切换选项卡时返回


对我来说,undefined无论如何它都会返回。您能详细说明如何使用吗?
tresf

undefined当光标未悬停任何元素时(或浏览器失去焦点时),它将返回。如果您要从控制台进行测试,则可能需要设置时间间隔
。– StefansArya,

谢谢。 setTimeout工作。我使用的是jsfiddle,您是对的,它从未遇到过悬停事件,因为每次单击播放时它都会重绘DOM。我建议为其他人添加此提示。
tresf

我不需要准确的鼠标位置,但我只想知道鼠标在没有事件对象的情况下在功能上是极右还是极左,因此您的解决方案适用于我的情况。.谢谢
Swap-IOS-Android

2

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

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

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

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


1

我实现了水平/垂直搜索(首先使div充满水平排列的垂直线链接,然后使div充满垂直排列的水平线链接,然后简单地看看哪个具有悬停状态),就像上面的Tim Down的想法一样,并且它的工作速度非常快。遗憾的是,它不适用于KDE上的Chrome 32。

jsfiddle.net/5XzeE/4/


除非用户明确移动鼠标,否则这些技巧显然不再起作用。:(
trusktr

1

您不必移动鼠标即可获取光标的位置。除mousemove以外的其他事件也报告此位置。这里以点击事件为例:

document.body.addEventListener('click',function(e)
{
    console.log("cursor-location: " + e.clientX + ',' + e.clientY);
});

1

嘲笑@SuperNova 的答案,这是一种使用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));


1

这是我的解决方案。它导出可以在任何地方使用的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
    document.addEventListener('mousemove', function (e) {
        window.currentMouseX = e.pageX;
        window.currentMouseY = e.pageY;
    });
}())

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


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

14
这是否还不需要用户移动鼠标?
Paul Hiemstra

0

我想我可能有一个合理的解决方案,而无需计算div和pixel..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);
}  
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.