【问题标题】: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,则在您四处移动时会出现错误的点。不过,这没什么大不了的,我们只是存储指针的“世界”坐标,然后让人们查询。

标签: javascript mouseevent dom-events


【解决方案1】:

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

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

注意不要这样做

【讨论】:

【解决方案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 读取鼠标位置,但现在已弃用。

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 2022-01-25
                    • 1970-01-01
                    • 1970-01-01
                    • 2011-10-06
                    • 1970-01-01
                    • 2017-12-25
                    相关资源
                    最近更新 更多