160

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

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

这可能吗?

4

17 回答 17

163

关于 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 样式的代码。将事件处理程序直接附加到文档会更好。

于 2008-11-27T02:53:36.613 回答
57

这是一个古老的问题,这里的答案似乎主要提倡使用mousedownmouseup跟踪是否按下按钮。但正如其他人指出的那样,mouseup只有在浏览器中执行时才会触发,这可能导致按钮状态丢失。

但是,MouseEvent (now) 指示当前按下了哪些按钮:

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

在 上注册时documentmousemove一旦光标重新进入浏览器,就会立即触发,因此如果用户在外部释放,那么一旦鼠标回到内部,状态就会更新。

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

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文档。

于 2018-02-25T05:58:54.183 回答
22

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

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.
}
于 2008-11-27T00:48:03.373 回答
13

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

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

于 2010-12-26T08:14:39.987 回答
7

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

<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 部分设置我自己的用户定义样式,但我无法让它工作。如果可以的话就更好了。

于 2016-02-04T23:32:57.173 回答
5

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

此外,您可能需要检查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 事件。

于 2017-12-21T18:47:58.703 回答
4

以下代码片段将在 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);
}
于 2008-11-27T00:34:42.477 回答
2

您可以结合@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
}
于 2008-11-27T00:54:48.460 回答
2

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

于 2008-11-29T22:29:21.250 回答
2

短而甜

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

添加到正文标签:

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

然后测试并执行myfunction()if downequals 1

onmousemove="if (down==1) myfunction();"
于 2012-08-12T14:07:50.577 回答
2

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

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

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

于 2014-01-04T20:12:41.163 回答
2

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

document.addEventListener('mousedown', (e) => console.log(e.buttons))

返回

代表一个或多个按钮的数字。对于同时按下一个以上的按钮,这些值会组合在一起(例如,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)
于 2019-07-24T10:47:47.097 回答
2

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

function mouseDown() {
    return document.body.matches(":active");
}
于 2021-05-24T18:23:29.147 回答
0

在 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();
});
于 2015-06-25T05:05:13.440 回答
0

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

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

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

不幸的是,在其中一种情况下,我不会得到该mouseup事件:

  • 用户同时按下键盘键和鼠标按钮,在浏览器窗口外释放鼠标按钮,然后释放键。
  • 用户同时按下两个鼠标按钮,释放一个鼠标按钮,然后释放另一个,都在浏览器窗口之外。
于 2017-09-20T08:14:51.350 回答
-1
        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;
        }

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

于 2013-07-04T14:49:49.100 回答
-3

好吧,您无法在活动结束后检查它是否已关闭,但您可以检查它是否已启动...如果已启动.. 则表示不再关闭:P 大声笑

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

于 2008-11-26T22:37:31.793 回答