关于javascript:为什么在某些情况下中键点击不会触发\\’click \\’?

Why does middle-click not trigger 'click' in several cases?

这是我所看到的行为的JSFiddle,与Chrome和FF中的中键单击和click事件有关。

'点击'有点儿作品

方法1:将click处理程序直接绑定到a元素,然后单击鼠标中键将在Chrome中触发该处理程序,但在FF中不会触发该处理程序。

1
2
3
$('div a').on('click', function(ev) {
    // middle click triggers this handler
});

方法2:将委派的click处理程序绑定到包含一个或多个adiv。在Chrome或FF中,中键单击不会触发此处理程序。

1
2
3
$('div').on('click', 'a', function(ev) {
    // middle click doesn't trigger this handler
});

如果div开始为空并且a元素稍后通过AJAX调用或由于某些用户输入而被填充,则此方法非常有价值。

"鼠标"作品

使用mouseup而不是click会导致方法1和2在两种浏览器中均起作用。

1
2
3
4
5
6
7
8
9
// Approach 1 w/ mouseup
$('div a').on('mouseup', function(ev) {
    // middle click **does** trigger this handler in Chrome and FF
});

// Approach 2 w/ mouseup
$('div').on('mouseup', 'a', function(ev) {
    // middle click **does** trigger this handler in Chrome and FF
});

这里是带有mouseup的JSFiddle。

这很有趣,在某些情况下可能有用,因为mouseup几乎是click。但是mouseup不是click,并且我追求click的行为。我不想创建click的hacky mousedown; setTimeout; mouseup模拟。

我很确定答案是"不",但是是否有一种跨浏览器的方式导致中键触发click处理程序?如果没有,原因为何?


通常会为鼠标左键触发click事件,但是,根据浏览器的不同,右键和/或中间按钮的click事件可能会或不会发生。

在Internet Explorer和Firefox中,不会为右键或中间按钮触发click事件。

因此,我们无法可靠地将click事件用于事件处理程序的中间或右键。

相反,要区分鼠标按钮,我们必须使用mousedown和mouseup事件,因为大多数浏览器的确会触发任何鼠标按钮的mousedown和mouseup事件。

在Firefox和Chrome event.which中的

应该包含一个数字,该数字指示按下了什么鼠标按钮(左是1,中是2,中3是右)。

另一方面,在Internet Explorer中,event.button表示单击了什么鼠标按钮(左侧是1,中间是4,右侧是2);

event.button在Firefox和其他浏览器中也应该可以使用,但是数字可能会略有不同(左为0,中为1,右为2)。

因此,总的来说,我们通常会执行以下操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
document.onmousedown = function(e) {
    var evt = e==null ? event : e;

    if (evt.which) { // if e.which, use 2 for middle button
        if (evt.which === 2) {
            // middle button clicked
        }
    } else if (evt.button) { // and if e.button, use 4
        if (evt.button === 4) {
            // middle button clicked
        }
    }
}

当jQuery标准化event.which时,您只需要在jQuery事件处理程序中使用它,就可以这样做:

1
2
3
4
5
$('div a').on('mousedown', function(e) {
    if (e.which === 2) {
        // middle button clicked          
    }
});

换句话说,您不能使用onclick事件,因此要模拟它,可以同时使用mousedown和mouseup。

您可以添加计时器以限制mousedown和mouseup事件之间允许的时间,甚至可以抛出mousemove处理程序来限制mousedown和mouseup事件之间的移动,并使鼠标移开时事件处理程序不会触发超过十个像素等。可能性几乎是无穷无尽的,所以这实际上不是问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
$('#test').on({
    mousedown: function(e) {
        if (e.which === 2) {
            $(this).data('down', true);
        }
    },
    mouseup: function(e) {
        if (e.which === 2 && $(this).data('down')) {
            alert('middle button clicked');
            $(this).data('down', false);
        }
    }
});


简短的回答:不。

问题是,您要捕获哪些中间点击?鼠标中键并不是要与当前页面互动,而是要在新标签页中打开链接。

Chrome浏览器目前也正在尝试删除此行为:https://code.google.com/p/chromium/issues/detail?id=255

目前,有关此主题的w3c邮件列表上有一个常规讨论:http://lists.w3.org/Archives/Public/www-dom/2013JulSep/0203.html

到目前为止,您可以在Firefox上在文档级别捕获Middleclick:

1
2
3
$(document).on('click', function(e){
    console.log(e);
});


我已经建立了一个工厂,用于使用香草JS创建中键鼠标单击处理程序,并在最新的Firefox和Chrome中工作:

1
2
3
4
5
6
7
8
9
10
11
const MiddleClickHandlerFactory = (node, handlerFn) => {
  node.addEventListener('mousedown', e => {
    if (e.button !== 1) return;
    e.preventDefault();   // stop default scrolling crap! Instead install ScrollAnywhere!

    const originalTarget = e.target;
    document.addEventListener('mouseup', e => {   // register on DOCUMENT to be sure it will fire even if we release it somewhere else
       if (e.target.isSameNode(originalTarget)) handlerFn(e);
    }, {capture: true, once: true, passive: true});
  }, true)
};