【问题标题】:JavaScript: Check if mouse button down?JavaScript:检查鼠标按钮是否按下?
【发布时间】:2008-11-26 22:29:23
【问题描述】:

有没有办法在 JavaScript 中检测鼠标按钮当前是否按下?

我知道“mousedown”事件,但这不是我需要的。按下鼠标按钮后的一段时间,我希望能够检测它是否仍然被按下。

这可能吗?

【问题讨论】:

  • 为什么你接受一个不能回答你问题的答案。注册 mousedown 和 mouseup 是错误的(因为您可以在浏览器之外使用 mouseup 并让它认为您仍在拖动)。解决您的问题并到达此页面完全没用
  • @Jack 它确实回答了我的问题。请阅读我的问题,然后阅读答案。显然,超过 100 人同意这是一个很好的答案。
  • 是的.. 但是我、alfred 和其他 8 人告诉你跟踪 mouseup 和 mousedown 不是正确的方法。正确答案应该包括分析您选择的处理程序中的事件对象,或者如果您需要时间驱动检查而不是事件驱动检查,则分析所有鼠标相关事件(如进入/退出)。
  • 这个问题是在 7 多年前提出并回答的。有新答案时我没有收到通知(但我为 cmets 收到通知)。写一个更好的答案,社区会投票给它顶部 :) 很多信息变得陈旧,事情发生了变化。
  • @TM。抱歉,死灵,但是...不,该信息永远不会到达顶部。一个非自我的答案,一旦被接受,就会永远保持在顶部。此外,“哦,这么多人投票给了这个”并不意味着答案是一个好答案。这只是意味着很多人看到了它,认为它看起来不错,并投了赞成票,因为它似乎对他们有用。

标签: javascript input mouse user-input input-devices


【解决方案1】:

关于 Pax 的解决方案:如果用户有意或无意地单击多个按钮,则它不起作用。不要问我是怎么知道的:-(。

正确的代码应该是这样的:

var mouseDown = 0;
document.body.onmousedown = function() { 
  ++mouseDown;
}
document.body.onmouseup = function() {
  --mouseDown;
}

通过这样的测试:

if(mouseDown){
  // crikey! isn't she a beauty?
}

如果您想知道按下了哪个按钮,请准备好将 mouseDown 设为一个计数器数组,并为单独的按钮分别计数:

// let's pretend that a mouse doesn't have more than 9 buttons
var mouseDown = [0, 0, 0, 0, 0, 0, 0, 0, 0],
    mouseDownCount = 0;
document.body.onmousedown = function(evt) { 
  ++mouseDown[evt.button];
  ++mouseDownCount;
}
document.body.onmouseup = function(evt) {
  --mouseDown[evt.button];
  --mouseDownCount;
}

现在您可以检查确切按下了哪些按钮:

if(mouseDownCount){
  // alright, let's lift the little bugger up!
  for(var i = 0; i < mouseDown.length; ++i){
    if(mouseDown[i]){
      // we found it right there!
    }
  }
}

现在请注意,上面的代码仅适用于向您传递从 0 及以上开始的按钮编号的标准兼容浏览器。 IE 使用当前按下按钮的位掩码:

  • 0 表示“没有按下任何内容”
  • 左侧 1 个
  • 2 右
  • 4 代表中间
  • 以及以上的任意组合,例如,5 代表左 + 中

因此请相应地调整您的代码!我把它留作练习。

请记住:IE 使用一个名为...“事件”的全局事件对象。

顺便提一下,IE 有一个对您有用的功能:当其他浏览器仅为鼠标按钮事件(onclick、onmousedown 和 onmouseup)发送“按钮”时,IE 也会使用 onmousemove 发送它。因此,当您需要知道按钮状态时,您可以开始监听 onmousemove,并在获得后立即检查 evt.button - 现在您知道按下了哪些鼠标按钮:

// for IE only!
document.body.onmousemove = function(){
  if(event.button){
    // aha! we caught a feisty little sheila!
  }
};

当然,如果她装死不动,你什么也得不到。

相关链接:

更新 #1:我不知道为什么我继承了 document.body 样式的代码。将事件处理程序直接附加到文档会更好。

【讨论】:

  • 经过测试,看来evt.button实际上在IE7的onmousemove上并不存在...
  • 我认为这在 Chrome 中不起作用,因为如果原始 mousedown 发生在滚动条上,Chrome 不会生成 mouseup 事件。 An example,来自this Chrome/Chromium issue。因此,如果有人使用滚动条,您的鼠标左键将永远按下! (在 Chrome 中)
  • 我喜欢你的解决方案,但是如果鼠标来自不同的应用程序说 ms 字并拖动一些文本怎么办。您将如何检测鼠标已按下?
  • 我不明白你为什么在第二个例子中增加 mousedown 数组 elts。为什么每个按钮都有一个计数器而不是每个按钮一个布尔值?
  • 这是一个非常受欢迎的问题(和答案)。我很惊讶这还没有出现,但你根本不需要存储鼠标数据。您只需将event.buttons 插入您正在使用的任何事件触发器,无需外部保存变量。我问了一个全新的问题(因为我的 mouseup 事件并不总是触发,所以这个解决方案对我不起作用)并在 5 分钟内得到了答案。
【解决方案2】:

这是一个老问题,这里的答案似乎大多主张使用mousedownmouseup 来跟踪按钮是否被按下。但正如其他人所指出的,mouseup 只会在浏览器中执行时触发,这可能会导致按钮状态丢失。

但是,MouseEvent(现在)表示当前按下了哪些按钮:

  • 对于所有现代浏览器(包括 Safari v11.1+ [iOS 上的 v11.3+]),请使用 MouseEvent.buttons
  • 对于 Safari MouseEvent.which(对于 Safari,buttons 将未定义)注意:which 使用与 buttons 不同的数字来进行右键和中键单击。

document 上注册时,mousemove 将在光标重新进入浏览器后立即触发,因此如果用户在外部释放,则只要鼠标回到内部,状态就会更新。

一个简单的实现可能如下所示:

var primaryMouseButtonDown = false;

function setPrimaryButtonState(e) {
  var flags = e.buttons !== undefined ? e.buttons : e.which;
  primaryMouseButtonDown = (flags & 1) === 1;
}

document.addEventListener("mousedown", setPrimaryButtonState);
document.addEventListener("mousemove", setPrimaryButtonState);
document.addEventListener("mouseup", setPrimaryButtonState);

该代码跟踪鼠标主键(通常是左键)的状态,忽略其他鼠标键的状态。

如果需要更复杂的场景(不同的按钮/多个按钮/控制键),请查看MouseEvent 文档。

【讨论】:

  • 我有一种情况,我期望在鼠标移动期间我应该让按钮代码为“1”,但它产生“7”,所有工作都在 Chrome 上。有人知道吗?
  • @VasilyHall 查看MouseEvent.buttons 的MDN 文档,7 似乎意味着它认为主要、次要和辅助按钮都被同时按下。我不确定为什么会出现这种情况 - 您使用的是高级鼠标吗?如果是这样,也许值得尝试一个基本的。如果您只是需要启动它,您可以使用bitwise check 来确保按下左按钮并忽略其他任何按钮。例如。 MouseEvent.buttons &amp; 1 === 1.
  • 谢谢,我在一个特殊的浏览器中使用我的 JavaScript:Adobe Illustrator 应用程序中的嵌入式 Chrome(ium?) - 我敢打赌,所有各种东西的组合都会以某种方式导致 7,虽然只有一个按钮被按下。看到这在我的应用程序中是如何保持一致的,我只是检查 1 或 7 以促进我的交互性。我要补充一点,虽然我确实使用 Logitech M570(或其他)轨迹球鼠标,但它在常规浏览器中正确注册了 1,但在 Illustrator 中正确注册了 7。
  • 从下往上阅读 Stack Overflow 页面的另一个例子。
【解决方案3】:

我认为最好的方法是自己记录鼠标按钮的状态,如下:

var mouseDown = 0;
document.body.onmousedown = function() { 
    mouseDown = 1;
}
document.body.onmouseup = function() {
    mouseDown = 0;
}

然后,稍后在您的代码中:

if (mouseDown == 1) {
    // the mouse is down, do what you have to do.
}

【讨论】:

  • +1,谢谢。我想我可能不得不求助于这个,但我希望有一些功能可以让你直接检查状态。
  • 是否有理由不使用布尔值?
  • @moala 我认为 Int 似乎打字更少,最终性能略好:jsperf.com/bool-vs-int
【解决方案4】:

解决方案不好。 可以在文档上“mousedown”,然后在浏览器外“mouseup”,在这种情况下,浏览器仍会认为鼠标已按下。

唯一好的解决方案是使用 IE.event 对象。

【讨论】:

  • 我知道您来自哪里,但拥有仅适用于 IE 的解决方案也不是一个好的解决方案。
  • @alfred 在某些情况下,了解 mousemove 是否超出窗口可能会有所帮助。 if(event.target.nodeName.toLowerCase==='html')down=0;
【解决方案5】:

我知道这是一篇旧帖子,但我认为使用鼠标向上/向下跟踪鼠标按钮感觉有点笨拙,所以我找到了可能吸引某些人的替代方法。

<style>
    div.myDiv:active {
        cursor: default;
    }
</style>

<script>
    function handleMove( div ) {
        var style = getComputedStyle( div );
        if (style.getPropertyValue('cursor') == 'default')
        {
            // You're down and moving here!
        }
    }
</script>

<div class='myDiv' onmousemove='handleMove(this);'>Click and drag me!</div>

:active 选择器对鼠标点击的处理比鼠标上/下要好得多,您只需要一种在 onmousemove 事件中读取该状态的方法。为此,我需要作弊并依赖于默认光标是“自动”这一事实,而我只是将其更改为“默认”,这是默认情况下自动选择的。

您可以使用 getComputedStyle 返回的对象中的任何内容,您可以将其用作标志而不会破坏页面的外观,例如边框颜色。

我本来想在 :active 部分设置我自己的用户定义样式,但我无法让它工作。如果可以的话就更好了。

【讨论】:

  • 感谢分享。我将这个想法用于拖放样式逻辑,但在 IE 上遇到了问题,不得不include additional logic
【解决方案6】:

如果您使用现有的鼠标事件处理程序在复杂页面中工作,我建议您在 capture 上处理事件(而不是气泡)。为此,只需将addEventListener 的第三个参数设置为true

此外,您可能需要检查 event.which 以确保您处理的是实际的用户交互而不是鼠标事件,例如elem.dispatchEvent(new Event('mousedown')).

var isMouseDown = false;

document.addEventListener('mousedown', function(event) { 
    if ( event.which ) isMouseDown = true;
}, true);

document.addEventListener('mouseup', function(event) { 
    if ( event.which ) isMouseDown = false;
}, true);

将处理程序添加到文档(或窗口)而不是 document.body 很重要,因为它可以确保 窗口外的 mouseup 事件仍然被记录。

【讨论】:

    【解决方案7】:

    以下 sn-p 将在 document.body 中的 mouseDown 事件发生 2 秒后尝试执行“doStuff”函数。如果用户抬起按钮,就会发生 mouseUp 事件并取消延迟执行。

    我建议对跨浏览器事件附加使用某种方法 - 显式设置 mousedown 和 mouseup 属性是为了简化示例。

    function doStuff() {
      // does something when mouse is down in body for longer than 2 seconds
    }
    
    var mousedownTimeout;
    
    document.body.onmousedown = function() { 
      mousedownTimeout = window.setTimeout(doStuff, 2000);
    }
    
    document.body.onmouseup = function() {
      window.clearTimeout(mousedownTimeout);
    }
    

    【讨论】:

    • 谢谢,但这并不是我想要的行为(尽管我可以看到我的问题表明这是我想要做的)。
    【解决方案8】:

    您可以结合@Pax 和我的答案来获取鼠标按下的持续时间:

    var mousedownTimeout,
        mousedown = 0;
    
    document.body.onmousedown = function() {
      mousedown = 0; 
      window.clearInterval(mousedownTimeout);
      mousedownTimeout = window.setInterval(function() { mousedown += 200 }, 200);
    }
    
    document.body.onmouseup = function() {
      mousedown = 0;
      window.clearInterval(mousedownTimeout);
    }
    

    然后:

    if (mousedown >= 2000) {
      // do something if the mousebutton has been down for at least 2 seconds
    }
    

    【讨论】:

    • 这不是一个坏主意,杰克。在将 mousedown 设置为 0 之前,是否需要在 onmouseup() 中清除 Interval()?我对在将其设置为 0 和停止计时器之间触发的计时器函数持谨慎态度,将超时设置为 200?在 onmousedown 中也是如此。
    • clearIntervals 的顺序不会产生影响,因为当前执行线程将在任何事件(包括计时器)触发之前完成。
    【解决方案9】:

    您需要处理 MouseDown 和 MouseUp 并设置一些标志或其他东西以“稍后”跟踪它...... :(

    【讨论】:

      【解决方案10】:

      又短又甜

      我不确定为什么以前的答案都不适合我,但我在灵光乍现的时刻想出了这个解决方案。它不仅有效,而且最优雅:

      添加到正文标签:

      onmouseup="down=0;" onmousedown="down=1;"
      

      如果down等于1,则测试并执行myfunction()

      onmousemove="if (down==1) myfunction();"
      

      【讨论】:

      • 你是新人,所以我会在这里帮助你一点。首先,在你的帖子中注意你的语法——我可能花在修复它上的时间比你投入的时间还多。其次,您的解决方案只是上面列出的其他解决方案的另一个版本 - 这不是什么新鲜事。第三,您的解决方案使用了一种称为“使用标志”的技术,Thomas Hansen 在上面提出了这种建议。请注意检查您的语法,并且在发布旧帖子时不要重复解决方案,而无需解释为什么其他解决方案不适合您。
      • 我做了,但是投票支持您的解决方案,因为它是有效的,而且您是 SO 新手
      【解决方案11】:

      使用 jQuery,以下解决方案甚至可以处理“拖出页面然后释放案例”。

      $(document).mousedown(function(e) {
          mouseDown = true;
      }).mouseup(function(e) {
          mouseDown = false;
      }).mouseleave(function(e) {
          mouseDown = false;
      });
      

      我不知道它如何处理多个鼠标按钮。 如果有办法在窗口外开始单击,然后将鼠标带入窗口,那么这可能也无法正常工作。

      【讨论】:

        【解决方案12】:

        使用MouseEvent api,检查按下的按钮,如果有的话:

        document.addEventListener('mousedown', (e) =&gt; console.log(e.buttons))

        Return:

        代表一个或多个按钮的数字。对于多个按钮 同时按下,这些值被组合(例如,3 是主要的 + 次要)。

        0 : No button or un-initialized
        1 : Primary button (usually the left button)
        2 : Secondary button (usually the right button)
        4 : Auxilary button (usually the mouse wheel button or middle button)
        8 : 4th button (typically the "Browser Back" button)
        16 : 5th button (typically the "Browser Forward" button)
        

        【讨论】:

          【解决方案13】:

          如果其他人遇到这种情况,您可以将.matches:active 选择器一起使用:

          function mouseDown() {
              return document.body.matches(":active");
          }
          

          【讨论】:

          • 一个警告:这对我在 Android 平板电脑上不起作用(如果我现在有一个要测试的 Android 手机,我怀疑它不会在 Android 手机上工作。)我仍在使用这个即使我错过了 mouseup/touchend 事件,帮助确保拖动操作结束的技巧,但我需要检查 document.body.matches(":active") 在拖动操作 开始 时是否为真,然后才使用它作为拖拽结束的额外测试。
          【解决方案14】:

          以下 jQuery 示例,当鼠标悬停在 $('.element') 上时,颜色会根据按下的鼠标按钮而变化。

          var clicableArea = {
              init: function () {
                  var self = this;
                  ('.element').mouseover(function (e) {
                      self.handlemouseClick(e, $(this));
                  }).mousedown(function (e) {
                      self.handlemouseClick(e, $(this));
                  });
              },
              handlemouseClick: function (e, element) {
                  if (e.buttons === 1) {//left button
                      element.css('background', '#f00');
                  }
                  if (e.buttons === 2) { //right buttom
                      element.css('background', 'none');
                  }
              }
          };
          $(document).ready(function () {
              clicableArea.init();
          });
          

          【讨论】:

            【解决方案15】:

            正如@Jack 所说,当mouseup 发生在浏览器窗口之外时,我们不知道...

            这段代码(几乎)对我有用:

            window.addEventListener('mouseup', mouseUpHandler, false);
            window.addEventListener('mousedown', mouseDownHandler, false);
            

            很遗憾,在其中一种情况下,我不会收到 mouseup 事件:

            • 用户同时按下键盘键和鼠标键,在浏览器窗口外释放鼠标键,然后释放键。
            • 用户同时按下两个鼠标按钮,释放一个鼠标按钮,然后释放另一个鼠标按钮,都在浏览器窗口之外。

            【讨论】:

              【解决方案16】:
                      var mousedown = 0;
                      $(function(){
                          document.onmousedown = function(e){
                              mousedown = mousedown | getWindowStyleButton(e);
                              e = e || window.event;
                              console.log("Button: " + e.button + " Which: " + e.which + " MouseDown: " + mousedown);
                          }
              
                          document.onmouseup = function(e){
                              mousedown = mousedown ^ getWindowStyleButton(e);
                              e = e || window.event;
                              console.log("Button: " + e.button + " Which: " + e.which + " MouseDown: " + mousedown);
                          }
              
                          document.oncontextmenu = function(e){
                              // to suppress oncontextmenu because it blocks
                              // a mouseup when two buttons are pressed and 
                              // the right-mouse button is released before
                              // the other button.
                              return false;
                          }
                      });
              
                      function getWindowStyleButton(e){
                          var button = 0;
                              if (e) {
                                  if (e.button === 0) button = 1;
                                  else if (e.button === 1) button = 4;
                                  else if (e.button === 2) button = 2;  
                              }else if (window.event){
                                  button = window.event.button;
                              }
                          return button;
                      }
              

              这个跨浏览器版本对我来说很好用。

              【讨论】:

                【解决方案17】:

                好吧,你不能在活动结束后检查它是否关闭,但你可以检查它是否是 Up... 如果它是 up.. 这意味着不再是 down :P lol

                所以用户按下按钮(onMouseDown 事件)......然后,您检查是否已启动(onMouseUp)。虽然它没有启动,但您可以做您需要的。

                【讨论】:

                • onMouseUp 不也是一个事件吗?您将如何检查 onMouseup 的“属性”?还是说谁的财产?
                • @Rohit:你不检查属性,你管理一个指示事件发生的标志......鼠标按钮是向上还是向下。
                猜你喜欢
                • 1970-01-01
                • 2020-08-24
                • 1970-01-01
                • 2020-06-28
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2021-03-07
                • 1970-01-01
                相关资源
                最近更新 更多