页面加载后是否可以在没有任何鼠标移动事件(不移动鼠标)的情况下使用 JavaScript 获取鼠标位置?
15 回答
真正的答案:不,这是不可能的。
好的,我刚刚想到了一个办法。用覆盖整个文档的 div 覆盖您的页面。在其中,创建(比如说)2,000 x 2,000 个<a>
元素(以便:hover
伪类可以在 IE 6 中工作,请参阅),每个元素大小为 1 个像素。为那些改变属性的元素创建一个 CSS:hover
规则<a>
(比如说font-family
)。在您的负载处理程序中,循环浏览 400 万个<a>
元素中的每一个,检查currentStyle
/getComputedStyle()
直到找到带有悬停字体的那个。从此元素推断回来以获取文档中的坐标。
注意不要这样做。
编辑 2020:这不再起作用。似乎是这样,浏览器供应商修补了这一点。因为大多数浏览器都依赖于 Chromium,所以它可能是它的核心。
旧答案:您也可以挂钩 mouseenter (此事件在页面重新加载后触发,当鼠标光标在页面内时)。扩展损坏的代码应该可以解决问题:
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。因此,您可以使用光标检查用户是否在您的页面上。
您可以做的是为光标的坐标创建变量,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);}
前面的代码每秒更新一次,并显示光标所在位置的消息。我希望这有帮助。
<a>
如果您渲染 2,000 x 2,000 个元素,@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 步开始重复。
这样,您最多需要重复这些步骤 11 次,考虑到您的屏幕不超过 2048 像素。
因此,您将生成最多 11 x 4 = 44 个<a>
元素。
如果您不需要将鼠标位置精确到像素,但说 10px 精度就可以了。您最多可以重复这些步骤 8 次,因此您最多需要绘制 8 x 4 = 32 个<a>
元素。
<a>
由于 DOM 通常很慢,因此生成然后销毁元素也不会执行。相反,您可以重复使用最初的 4 个<a>
元素,并在循环执行步骤时调整它们的、top
和。left
width
height
现在,创建 4<a>
也是一种矫枉过正。相反,您可以在每个矩形中<a>
进行测试时重复使用相同的一个元素。getComputedStyle()
因此,不要将搜索区域拆分为 2 x 2元素,只需通过使用和样式属性移动它来<a>
重用单个元素。<a>
top
left
因此,您只需将单个<a>
元素更改其width
和height
最大值 11 次,并将其top
和left
最大值更改 44 次,您将获得准确的鼠标位置。
您可以尝试类似于 Tim Down 建议的方法 - 但不要在屏幕上为每个像素创建元素,而是仅创建 2-4 个元素(框),并动态更改它们的位置、宽度、高度以划分屏幕上可能的位置通过 2-4 递归,从而快速找到鼠标的实际位置。
例如 - 第一个元素占据屏幕的右半部分和左半部分,然后是上半部分和下半部分。到目前为止,我们已经知道鼠标位于屏幕的哪个四分之一,可以重复 - 发现这个空间的哪个四分之一......
这是我的解决方案。它导出可以在任何地方使用的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
最简单的解决方案,但不是 100% 准确
$(':hover').last().offset()
结果:{top: 148, left: 62.5}
结果取决于最近的元素大小,并undefined
在用户切换选项卡时返回
是的,这是可能的。
如果您将“鼠标悬停”事件添加到文档中,它将立即触发并且您可以获得鼠标位置,当然如果鼠标指针位于文档上方。
document.addEventListener('mouseover', setInitialMousePos, false);
function setInitialMousePos( event ) {
console.log( event.clientX, event.clientY);
document.removeEventListener('mouseover', setInitialMousePos, false);
}
以前可以读取鼠标位置,window.event
但现在已弃用。
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;
}
我实现了一个横向/纵向的搜索,(先做一个横向排列的全垂直线链接的div,然后再做一个纵向排列的全横向线链接的div,简单看看哪个有hover状态)就像上面Tim Down的想法,和它工作得非常快。可悲的是,在 KDE 上的 Chrome 32 上不起作用。
jsfiddle.net/5XzeE/4/
您不必移动鼠标来获取光标的位置。除了mousemove之外的事件也会报告该位置。这里以点击事件为例:
document.body.addEventListener('click',function(e)
{
console.log("cursor-location: " + e.clientX + ',' + e.clientY);
});
在@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));
不是鼠标位置,但是,如果您正在寻找当前光标位置(用于获取最后输入的字符等用例),那么下面的代码片段可以正常工作。
这将为您提供与文本内容相关的光标索引。
window.getSelection().getRangeAt(0).startOffset
我设想也许您有一个带有计时器的父页面,并且在一定时间或任务完成后,您将用户转发到新页面。现在您需要光标位置,因为它们正在等待,它们不一定会触摸鼠标。因此,使用标准事件在父页面上跟踪鼠标,并在 get 或 post 变量中将最后一个值传递给新页面。
您可以在父页面上使用 JHarding 的代码,以便在全局变量中始终提供最新位置:
var cursorX;
var cursorY;
document.onmousemove = function(e){
cursorX = e.pageX;
cursorY = e.pageY;
}
这不会帮助通过您的父页面以外的方式导航到此页面的用户。
我想我可能有一个合理的解决方案,不计算 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);
}