如何在没有事件的情况下获取鼠标位置(不移动鼠标)?
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】:
您可以做的是为光标的x
和y
坐标创建变量,在鼠标移动时更新它们,并在间隔上调用一个函数来对存储的位置执行您需要的操作。
当然,这样做的缺点是至少需要鼠标进行一次初始移动才能使其工作。只要光标至少更新一次位置,无论它是否再次移动,我们都能找到它的位置。
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
事件添加一个函数,将x
和y
设置回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>
元素即可:
<a>
元素
第 3 步:使用 getComputedStyle()
函数确定鼠标悬停在哪个矩形中
第 4 步:将搜索区域缩小到该矩形,然后从第 2 步开始重复。
考虑到您的屏幕宽度不超过 2048 像素,您最多需要重复这些步骤 11 次。
因此您将生成最多 11 x 4 = 44 个<a>
元素。
如果您不需要将鼠标位置精确到一个像素,但说 10px 精度是可以的。您最多会重复这些步骤 8 次,因此您最多需要绘制 8 x 4 = 32 <a>
元素。
同时生成然后销毁<a>
元素也不会执行,因为 DOM 通常很慢。相反,您可以重复使用最初的 4 个<a>
元素,并在循环执行步骤时调整它们的top
、left
、width
和height
。
现在,创建 4 个<a>
也是一种矫枉过正。相反,您可以在每个矩形中测试getComputedStyle()
时重复使用相同的<a>
元素。因此,不要将搜索区域拆分为 2 x 2 <a>
元素,只需使用 top
和 left
样式属性移动单个 <a>
元素即可。
因此,您只需将单个 <a>
元素更改其 width
和 height
最多 11 次,并将其 top
和 left
最多更改 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.currentMouseX 和 window.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 中获取鼠标按钮状态?