jQuery绑定单击*任何*,但*元素*


72

假设有一些元素在浮动,当我单击除指定的元素(例如div#special)以外的任何内容(divs,body等)时,我正在尝试执行一些操作。

我想知道除了以下我能想到的方法之外,还有没有更好的方法来实现这一目标...

$(document).bind('click', function(e) {
    get mouse position x, y
    get the element (div#special in this case) position x, y
    get the element width and height
    determine if the mouse is inside the element
    if(inside)
        do nothing
    else
        do something
});


$(':not(div#special)').bind('click', function(e) { ...api.jquery.com/not-selector
Jim Schubert

@JimSchubert:应该起作用,我将其发布为答案-它比可能重复的答案更简单。但是,它似乎效率很低。
Wesley Murch

1
@韦斯利:但这是不正确的。事件处理程序还将绑定到内部元素div#special...
Felix Kling

4
@吉姆::not(div#special, div#special *)会的。但是,我将避免将事件处理程序绑定到每个元素。在这种情况下,使用事件委托要好得多。
菲利克斯·克林

Answers:


118

要处理“除了单击元素时执行此操作”情况,一般的方法是在上添加一个事件处理程序,以document处理“执行此操作”的情况,然后向“ except this”元素添加另一个事件处理程序,防止click事件冒泡到document;

$('#special').on('click', function(e) {
    e.stopPropagation();
});

$(document).on('click', function (e) {
 // Do whatever you want; the event that'd fire if the "special" element has been clicked on has been cancelled.
});

请参阅event.stopPropagation()文档。对于那些使用jQuery 1.7之前版本的人(就像问这个问题的情况一样),您将无法使用on();。代替简单的替换2种的用途on()bind(); 在这种情况下,签名是相同的。

演示在这里;http://jsfiddle.net/HBbVC/


6
没有进攻,但基本上是在重复我给挂了相同的答案:stackoverflow.com/questions/152975/...
费利克斯·克林

4
@Felix:我现在可以看到这一点,但你没有张贴的评论时,我开始写答复:(。
马特

尽管我在其他任何地方都没有问题,但似乎无法在移动Safari上运行。
dgig

您的答案与此处的Hugo Silva的答案相结合,解决了我在Safari上的特定问题。移动设备不会总是允许非锚上的“单击”动作,因此您必须对其进行定义(似乎(请参阅他的回答以获取适当的解释)):stackoverflow.com/questions/10722730/…–
dgig

如果定义了针对其他元素的事件处理程序以防止冒泡,则此方法将无效。这将导致那些要素被认为是误报。Imho,一种更好/完全可靠的解决方案是定义一个文档处理程序(已完成),但将其定义为在捕获阶段而不是冒泡阶段触发。您必须在上述处理程序中主动过滤要跳过/传递的元素。您可以省略其他处理程序。
Geert-Jan 2013年

46

你也可以

$(document).bind('click', function(e) {
  if(!$(e.target).is('#special')) {
    // do something
  }
});

或者,如果div#special具有子元素,则可以执行

$(document).bind('click', function(e) {
  if($(e.target).closest('#special').length === 0) {
    // do something
  }
});

5

过去我是这样做的:

jQuery("body").bind("click", function(e)
{
    var obj = (e.target ? e.target : e.srcElement);
    if (obj.tagName != 'div' && obj.id != 'special')
    {
        // Perform your click action. 
        return false;
    }
});

仅当您未单击div#special时才会执行。老实说,也许有更好的方法可以这样做,但这对我有用。


2
您不需要进行测试e.target。它将一直存在,jQuery规范了事件对象。如果div#special包含其他元素,它将不起作用。
菲利克斯·克林

1

您需要进行不同的绑定,因此无需在一个函数中处理所有这些单击

$('body').bind('click', function(e){
  bodyClickEvent();
});
$('div.floating').bind('click',function(e){
  elementClickEvent(this);
  e.stopPropagation(); //prevents bodyClickEvent
});
  $('div#special').bind('click', function(){
  e.stopPropagation(); //prevents bodyClickEvent
});

1

我今天写这篇文章是为了解决我遇到的一个问题,因为我不喜欢一直将单击事件绑定到文档,因此对于我的情况,使用函数的回调是可行的。

$('#button').click(function(){
        //when the notification icon is clicked open the menu
        $('#menu').slideToggle('slow', function(){
            //then bind the close event to html so it closes when you mouse off it.
            $('html').bind('click', function(e){
                $('#menu').slideToggle('slow', function(){
                    //once html has been clicked and the menu has closed, unbind the html click so nothing else has to lag up
                    $('html').unbind('click');
                });
            });
            $('#menu').bind('click', function(e){
                //as when we click inside the menu it bubbles up and closes the menu when it hits html we have to stop the propagation while its open
                e.stopPropagation();
                //once propagation has been successful! and not letting the menu open/close we can unbind this as we dont need it!
                $('#menu').unbind('click');
            });
        });
    });

0

我曾经比其他答案更轻松地解决了此问题,但不必担心点击确实会落在DOM-Tree上

只需检查您的元素是否悬停;)

$(document).on('click', function (e) {

  if($('#special:hover').length > 0){
    // on our special element
  }else{
    // not on our special element
  }

});

干杯

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.