【问题标题】:Detect middle button click (scroll button) with jQuery用jQuery检测中间按钮点击(滚动按钮)
【发布时间】:2011-07-20 12:44:22
【问题描述】:

我有一个带有标签的列表,可以在点击时播放一些 mp3 文件。使用 jQuery 绑定“click”事件时它工作正常:

$oo.data({'__mp3play':true,'wapiHandle':h+0,'wapiIndex':o.ajaxPlayList[h].length})
           .bind( 'click', function()
            { var wh = $j(this).data('wapiHandle');
              if( typeof o.regObjects[wh] == 'object' && o.regObjects[wh].play(this.href))
               { return false; }
            });

单击鼠标左键时: 加载我的 Flash 插件时它会禁用默认处理,否则它将正常打开。

但是: 当我使用鼠标的滚动按钮并单击它时,不会触发单击事件并且链接正常打开。

我曾尝试使用 mousedown 或 mouseup 事件,但没有帮助,链接总是正常打开,副作用是音乐也开始使用 Flash 播放器播放。

另外preventDefault() 根本不起作用。

谁能告诉我如何检测鼠标中键点击(滚动按钮点击)?

感谢您的 cmets。

PS:我已经尝试过有关此站点上可用的“中间按钮”的其他解决方案。

在所有类型的浏览器中测试,结果相同。

编辑: 这也不起作用,使用鼠标中键时链接将正常打开。使用鼠标左键时,没有任何反应。

$oo.bind( 'mousedown click mouseup', function(e)
{ e.preventDefault(); e.stopPropagation(); return false; });

【问题讨论】:

  • 您为什么希望click 被调用以进行中键单击?它们不一样-您不会期望右键单击它吗?你用mousedown 方法尝试了什么?您是否检查了event.which 属性以确定按下了哪个按钮?
  • 中键的处理方式与鼠标左键相同,A-tag 将被打开,因此您可以假设鼠标左键与中键相同——点击。如果不是,就像你刚才说的,中间点击事件的名称是什么? Event.which 没有任何区别,您可以测试是否按下了中间按钮,但您不能抑制中间按钮的默认行为,因为涉及另一个事件?链接仍然正常打开。
  • 您的假设是错误的 - 仅仅因为鼠标左键单击显示类似于中键单击的行为并不意味着它们在内部是相同的。事实上,它们不是 - 单击鼠标中键时不会触发 click。但是,事实证明您对preventDefault()stopPropagation() 没有任何影响是正确的,我目前想不出任何解决方法。这是一个fiddle,它显示了我使用mousedownmouseup 取得了多大的进展
  • 查看我的答案并在下面摆弄,我发现了一个论坛帖子,它提出了一种让它工作的方法。
  • @AdvaitJunnarkar 不,因为接受的答案提供了相同的解决方案(检测)并且还抑制了仅 IE 的行为(仅检测是不够的)。这是一个相当古老的问题,已有 8 年历史,部分与 IE 相关。 IE 已经死了,历史,那么为什么要使用“新”解决方案呢?已经有一个更好、更先进的解决方案。

标签: jquery button click scroll


【解决方案1】:

好吧,经过快速测试,这三个似乎是按如下顺序排列的:

  • 左 - 1
  • 中 - 2
  • 右 - 3

如果你有:

$(document).mousedown(function(e){
    switch(e.which)
    {
        case 1:
            //left Click
        break;
        case 2:
            //middle Click
        break;
        case 3:
            //right Click
        break;
    }
    return true;// to allow the browser to know that we handled it.
});

【讨论】:

  • 我知道,我知道,但问题并非如此
【解决方案2】:

不要mousedown 事件期间触发点击操作。它忽略了事件管道的其余部分,违背了当前的用户期望和设计实践。

问题

以下是每种点击类型触发的事件的正常顺序:

$(document).on("mousedown mouseup click focus blur",function(e) {
  console.log("{" + e.which + ":" + e.type + "}"); 
});    

通常,我们处理最后一个 click 事件,因为它表示用户最终打算继续当前操作。

当指针设备按钮(通常是鼠标的主按钮)在单个元素按下和释放时触发click事件>.

不幸的是,鼠标中键不会触发这样的事件(可能是因为这样做会迫使开发人员监听点击事件来区分多个可能的调用)。但是,如果我们想针对中间点击连接操作,我们应该遵循相同的 UX 期望。

解决方案

我们将监听mousedown 事件并立即为mouseup 事件附加一次性使用处理程序。如果按下中间键并且元素匹配,我们将trigger我们自己的custom event 类型为middleclick,我们将seed from the original event

$(document).on("mousedown", function (e1) {
  $(document).one("mouseup", function (e2) {
    if (e1.which == 2 && e1.target == e2.target) {
      var e3 = $.event.fix(e2);
      e3.type = "middleclick";
      $(e2.target).trigger(e3)
    }
  });
});

这将有助于区分 if 中间按钮是否被单击以及在这种情况下我们希望如何处理它,因此我们可以为我们的自定义事件类型设置一个侦听器,如下所示:

$(document).on("middleclick", function (e) {
    console.log("{" + e.target.nodeName.toLowerCase() + ":" + e.type + "}"); 
});

jsFiddle 和 Stack Snippets 中的工作演示:

$(document).on("mousedown", function (e1) {
  $(document).one("mouseup", function (e2) {
    if (e1.which == 2 && e1.target == e2.target) {
    	var e3 = $.event.fix(e2);
      e3.type = "middleclick";
      $(e2.target).trigger(e3)
    }
  });
});

$(document).on("middleclick", function (e) {
  console.log("{" + e.target.nodeName.toLowerCase() + ":" + e.type + "}"); 
});

$(document).on("mousedown mouseup click focus blur",function(e) {
  console.log("{" + e.which + ":" + e.type + "}"); 
}); 
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.js"></script>

<div  style="background:#31965a;color:white;width:100px;height:100px;line-height:100px;text-align:center;">
  Click Me!
</div>

* 在 Chrome、FF、Edge 和 IE11 中测试

【讨论】:

  • 感谢您的回答,但存在一些问题。你写了; “请不要在 mousedown 事件期间触发点击操作。它会忽略事件管道的其余部分,并违背当前的用户期望和设计实践。”呃,起初,它不会触发任何东西,它本身不会导致硬件事件,也不会触发点击事件,但是它会处理事件并可以取消事件。并且由于您没有取消单击路径中的任何内容,因此当有其他附加的事件处理程序时,可能会导致不可预知的结果。我已经发布了一个解决方案/解决方法 2 这个。
  • @Codebeat,我感谢您的评论(但不确定是否反对)。我不确定我们的解决方案是否正在寻求解决相同的问题。我的观点是,这个答案实际上处理了一个中间 mouse click 事件,而不仅仅是一个中间 mouse mousedown 事件。当用户单击并释放同一元素时,会发生单击事件。当您在一个链接上单击鼠标中键时,在所有浏览器中它会在您放手时打开该链接,而不是在您按下按钮时打开。它让你有时间取消。如果你想复制这个功能,你需要这个 asr
  • 这个问题已有 7 年历史,也是答案,我相信我做了 '$.browser.msie ? “mousedown”:“点击”是有原因的。此外,我使用文档元素(像您一样)来预览操作,以便在事件到达焦点元素之前。这就是我取消活动的原因。如果您取消一个事件,所有其他相关事件都将被忽略,因此根本没有点击,因为该操作尚未完成。在您的示例中,您没有取消任何内容,这就是为什么您仍然会收到有关文档和焦点元素的所有事件。目标是在行动将要进行时抑制行为。
  • 我昨天看到我的问题和答案被否决了,希望你不是这样做的人,因为你对所有的挫折感到愤怒。我不知道你的问题到底是什么,为什么你想做你想做的,有一个额外的处理程序等等。你的答案必须是评论。 7年前mousedown(iE)和click(其他)的差异是有原因的。同样,目标是在任何链接上处理操作之前抑制硬件行为(IE 要求 7 年前),并避免需要在每个元素上绑定额外的事件处理程序。 .....
  • ........如果你不取消活动,它根本不起作用。而且我不会触发点击等。真的,我不明白你的意思是什么,也许你不明白事件是如何运作的。而且,这不是问题的答案。您想讨论答案而不是问题,这可能是评论。
【解决方案3】:

好的,我想我明白了。这是fiddle that seems to work。诀窍(至少在 FF4 中)似乎是将点击处理程序绑定到 document 并让它停止传播。

$(document).click(function(e){
        //not checking for the right click will prevent the context-menu from showing, you may or may not want to do that
        if (e.which != 3) { 
            e.preventDefault();
            return false;
        }
    });

This solution was found on this forum page.

【讨论】:

    【解决方案4】:

    好吧,伙计们,

    感谢您的意见。 '@no.good.at.coding' 有一个很好的解决方案,但不适用于 IE(请参阅本文后面的内容),但它是一个很好的起点。我把他的代码改成这样:

    // Avoid relations will be opened in extra tab when clicking middle-scroll-button to open it
    $(document).bind($.browser.msie ? "mousedown" : "click", function(e)
    {
        if (e.which == 2 && e.target.tagName == 'A') 
        {
            var bIE = $.browser.msie,
                $o = $(e.target),
                oe = $o.data('events'),
                b = true,
                f = function(){};
    
            if (typeof oe == 'object' && oe['click']) {
                f = function(){ $o.trigger('click'); }
            } else {
                b = (typeof $o[0].href == 'string' && ($o[0].target == undefined || $o[0].target == '' || $o[0].target == '_self'));
                if (b) { 
                    f = function () { window.location.href=$o[0].href; };
                }
            }
    
            if (!b) { return; }
    
            e.stopImmediatePropagation();
            e.stopPropagation();
            e.preventDefault();
    
            if (bIE)
            {
                if (!window.__swcp__) { 
                    window.__swcp__= $('<div style="position:fixed;top:0px;left:0px;width:100%;height:100%;background:#000;display:block;z-index:9999;opacity:0.01;filter:alpha(opacity:1);" />').appendTo('body'); 
                }
                window.__swcp__.show();
            }
    
            setTimeout(f, 50);
            if (bIE) { 
                setTimeout( function() { window.__swcp__.hide(); }, 1000 );
            }
    
            return false;
        }
    });
    

    现在中键的作用类似于鼠标左键。正如你所看到的 IE 需要更多,我们必须将链接标签取消焦点 1 秒钟以避免它会在额外的选项卡中打开。我在这里使用一种简单的方法来执行此操作,创建一个“眼睛”透明 div(不透明度 = 0.01),它将放置在窗口内容上,因此页面上的任何链接都将不聚焦。 用户不会注意到任何区别,除了鼠标指针可以从指针变为默认指针,一秒钟后它又变回指针(仅限 IE)。我可以忍受这一点。

    我接受这个作为答案,但如果您有更好的想法,请告诉我。

    【讨论】:

    • 请注意 jquery.browser 已被弃用。 api.jquery.com/jQuery.browser
    • Frisberarian
    • 对不起,如果我的编辑看起来很激进,但它很难理解。我试图让变量保持原样,但它们确实应该重命名,我认为一些重构,例如重用浏览器检查可能是个好主意。
    • 谢谢 Nenotiep。嗯,有些东西是你喜欢的风格。我不喜欢 accolade 风格,总是难以阅读,因为你不能直接看到语句,永远不明白为什么它们彼此不一致。变量,我知道,但它的 javascript 必须是紧凑的速度。现在我使用谷歌附件编译器来缩小脚本。此外,查看代码中发生的事情而不是查看变量名总是很重要的。当然,一个清晰的变量名可以让事情变得清晰,因为 javascript 没有声明类型,它可以是任何东西。不要过度依赖 2 变量名称。
    • ..... (继续上面的评论)当你能读到这个时,你几乎可以读到任何东西。我总是使用以变量的预期类型(字母)开头的 var 名称。 o = 对象,$ = jQuery 对象,b = 布尔值,s = 字符串,i = 整数,e = 事件,f = 函数等
    【解决方案5】:

    使用 HTML5 执行此操作的正确方法是使用 auxclick event

    例如,要完全禁用鼠标中键单击元素

        $element.on("auxclick.disablemiddleclick", function(e)
        {
            // https://developer.mozilla.org/en-US/docs/Web/API/Element/auxclick_event
            if (e.which === 2 && e.cancelable) // disable middle button click
            {
                e.preventDefault();
                e.stopPropagation();
                e.stopImmediatePropagation();
                console.log("disabled middle click, e=", e);
            }
        });
    

    (“auxclick”处理程序名称的后缀旨在允许使用$element.off("auxclick.disablemiddleclick") 轻松删除此处理程序,而无需跟踪函数引用。)

    【讨论】:

    • 当今的有效答案(查看支持版本号)但是这个问题已经有将近 10 年的历史了!例如,10 年前,IE 不支持此功能。
    • 是的,MSIE 和 HTML5 匹配的唯一方法是“MSIE 不支持 HTML5”这句话。
    【解决方案6】:

    e.which 应该这样做:

    简单示例:

    $(document).ready(function(){
        $(document).mousedown(function(e){
             alert(e.which); // ##=> left
        }) 
    })
    

    【讨论】:

    • 这不是问题的答案,也根本不是答案
    • 不,它没有 - 问题是浏览器处理中间点击,当链接被中间点击时,它仍然打开一个新标签/窗口。在上面的 cmets 中查看我的小提琴。
    【解决方案7】:

    如果您(像我一样)因为来自客户的奇怪的中间点击错误而发现此问题。而且您只希望任何中间或右键单击都像左键一样

    忘记 IE 的所有蹩脚代码吧。

    又短又甜:

    $(document).click(function(e){
      // checking for any non left click and convert to left click.
      if (e.which != 1) { 
        e.which = 1;
      }
    });
    

    显然,如果您需要更多的歧视,您可以执行以下操作:

    $('a.no-non-left-clickies').click(function(e){
      // checking for any non left click and convert to left click.
      if (e.which != 1) { 
        e.which = 1;
      }
    });
    

    【讨论】:

    • 好吧,我更详细地查看了您最初的问题,我发现您确实需要比我提到的更多的 IE 垃圾,但是,总的来说,我的声明仍然有效。如果你想要一个 quick-o-change-o 将中键或右键转换为左键,上面的简单代码将适用于我测试过的所有浏览器。
    • 没有尝试过你的解决方案,但它是否也避免了打开一个新页面?
    猜你喜欢
    • 1970-01-01
    • 2011-12-11
    • 2020-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多