【问题标题】:jQuery blur should not fire if div is clicked/focused如果单击/聚焦 div,jQuery 模糊不应触发
【发布时间】:2012-06-23 22:34:23
【问题描述】:

我有一个带有模糊事件的标准文本输入。当单击文档中的任何内容(输入 AND <div id='show-anyways'></div> 除外)时,应触发 blur 事件。

我的问题是我不知道如何添加<div id='show-anyways'></div>来否定模糊事件功能。

希望我已经对自己进行了充分的解释,我知道这有点奇怪。如果您需要更多信息,请告诉我。

【问题讨论】:

  • 请显示您目前的编码。
  • 您需要e.preventDefaulte.stopPropagation,或者确定哪个被点击并在它击中目标之前停止冒泡。我觉得设计缺陷是您在 DOM 上有一个模糊事件处理程序?我理解的对吗?

标签: jquery input blur


【解决方案1】:

使用事件目标来确定点击了什么。如果元素是 DIV 或 Input,以下将跟踪文档上的所有点击,并且不会触发 blur()。

var $input=$( '#MY-Input-ID');

$(document).click(function(evt){
   var $tgt=$(evt.target);
   if( !$tgt.is( '#show-anyways') && !$tgt.is($input) ){
         $input.blur()
    }
})

它不会在设置了任何 preventPropogation 的元素上触发。

【讨论】:

  • 我实际上不得不使用 $(document).click 作为我的解决方案,因为如果输入点击/焦点序列,原始 input.blur 事件将不会触发 -> #show-anyways -> 文档。单击。因此,#show-anyways 和 document.click 之间的事件不会触发 input.blur 事件...
  • 注意:检查 div 及其所有子项中的点击的一个好方法是将&& !$tgt.is($('*', $('#show-anyways'))) 添加到上述 click 函数中的条件语句中。
  • @garromark 只检查元素的后代...... $tgt.closest('#show-anyways').length 将检查后代和元素.. 不知道为什么我没有使用那个
【解决方案2】:

更新:必须完全重写我的解决方案。 blur 事件处理程序附加到失去焦点的事件:如果它类似于mouseout 事件,我们可以知道哪个元素将获得焦点,但没有这样的运气。所以我们不得不求助于捕获.click 事件——并基于它触发一些函数,而不是监听blur 事件。

var inputIsBlurred = function() { 
   console.log('Run away!!!');
};
$(document).click(function(e){
  var $target = $(e.target);
  console.log($target);
  if ($target.is('#some_input') // fired by an input - no special effects
      || $target.is('#show-anyways') // fired by 'show-anyways' div
      || $target.parents('#show-anyways').length > 0 // ... or its children
  ) {
      return true; // move along, nothing to do here
  }
  inputIsBlurred();
});​

这是a fiddle 玩。很抱歉我的原始答案造成的混乱。 (

【讨论】:

    【解决方案3】:

    其他解决方案缺少一些内容。最重要的是,您需要在调用模糊事件之前检查输入是否聚焦。另一件事是,不仅在您单击其他地方时会调用模糊事件:您还可以在转到浏览器中的另一个选项卡时调用它,或者如果您点击 tabshift + tab 转到下一个/上一个输入。最后,当您检查目标元素是否是您的模糊事件的异常(它可以是您的异常的子元素)时,您需要考虑使用 jQuery 函数closest()

    所以,我想出了这个 jQuery 原型函数:

    $.fn.extend({
    
        blurIfNot : function(options, handler)
        {
            var defaults =
            {
                except : [],
                maxParent : null // A DOM element within which
                                 // a matching element may be found
            };
            var opt = $.extend({}, defaults, options);
            var time = new Date().getTime();
            
            this.each(function()
            {
                var thisInp = $(this);
                thisInp[0].blurIfNot = {};
                time += 1000000000000;
                
                var except = opt.except;
                
                if ($.isFunction(opt.except))
                { except = opt.except.call(thisInp[0]); }
                
                function fire_blur_event(_tar, evt, mousedown)
                {
                    var proceed = true;
                    
                    for (var i in except)
                    {
                        if (_tar.is(thisInp) ||
                        _tar.closest(except[i], opt.maxParent).length)
                        {
                            proceed = false;
                            break;
                        }
                    }
                    if (proceed)
                    {
                        thisInp[0].blurIfNot.focus = false;
                        handler.call(thisInp[0], evt);
                    }
                    else if (mousedown)
                    {
                        $('html').one('mouseup', function(e)
                        {
                            thisInp[0].focus();
                        });
                    }
                }
                
                if (!thisInp[0].blurIfNot.isset)
                {
                    $('html').mousedown(function(e)
                    {
                        if (thisInp[0].blurIfNot.focus)
                        {
                            var tar = $(e.target);
                            
                            if (!tar.is('input'))
                            { fire_blur_event(tar, e, true); }
                        }
                    });
                    
                    $(window).blur(function(e)
                    {
                        if (thisInp[0].blurIfNot.focus)
                        {
                            thisInp[0].blurIfNot.focus = false;
                            handler.call(thisInp[0], e);
                        }
                    });
                }
                else
                {   // to be able to update the input event if you have
                    // created new inputs dynamically
                    $('input').off('focus.blufIfNot' + time);
                }
                
                $('input').on('focus.blurIfNot' + time, function(e)
                {
                    var tar = $(e.target);
                    
                    if (tar[0] == thisInp[0])
                    { thisInp[0].blurIfNot.focus = true; }
                    
                    else if (thisInp[0].blurIfNot.focus)
                    { fire_blur_event(tar, e); }
                });
                
                thisInp[0].blurIfNot.isset = true;
            });
            return this;
        }
    });
    
    $('#input_blur_if_not').blurIfNot(
    {
        except : [
            $('.autocomplete'), $('.question')
        ],
        // You can also define the elements with a function:
        // except : function()
        // {
        //     return [ $(this).parent().find('.autocomplete') ];
        // },
        maxParent : $('#parent')[0] // optional
    },
    function(e)
    {
        var rand = Math.random();
        
        $('#test').css('padding', rand * 100 + "px").
        html(rand + " blur !");
    });
    .autocomplete {
        background: #eee;
    }
    .autocomplete, input {
        width: 200px;
        padding: 3px;
        border: 1px solid #555;
    }
    .question {
        display:inline-block;
        border-radius:50%;
        background:#137dba;
        color:#fff;
        font-weight:bold;
        padding:2px 7px;
        cursor:pointer;
    }
    #test {
        position:absolute;
        top:0;
        left:260px;
        color:red;
        font-weight:bold;
        padding:10px 0;
        vertical-align:bottom;
    }
    <script src="http://code.jquery.com/jquery-latest.js"></script>
    
    <div id="parent">
        
        <input value="an input" />
        <br><br>
        <input id="input_blur_if_not" value="input with autocomplete menu" />
        
        <div class="question">?</div>
        <div class="autocomplete">
            <div>option 1</div>
            <div>option 2</div>
        </div>
        <br>
        <input value="another input" />
        <div id="test"></div>
      
    </div>

    在 Chrome 和 IE11 中测试。如果您需要更多解释,请随时发表评论。

    【讨论】:

    • 非常全面。感谢您花时间测试和发布此内容。
    【解决方案4】:

    可以尝试添加一些逻辑吗?

    $('input').blur(function(e){
    var tester = e.target;
    if ($(tester).attr('id') == 'show-anyways'){
    return false;
    }
    else {
    // do something?
    }
    
    });
    

    这基本上在模糊发生时触发,它检查点击/定位的内容,如果它恰好是显示,那么它将返回 false 并停止执行任何操作。但如果它不显示,那么它可以做你的模糊事件吗?

    未经测试,但这是你的意思吗?

    【讨论】:

    • 这正是我的意思,但是 e.target 在模糊事件中为我返回“输入”...所以我无法得出您的解决方案是什么...
    • 找到了 - 事件中的构造是 originalEvent.explicitOriginalTarget
    • 可悲的是 originalEvent.explicitOriginalTarget 只是 Gecko。
    • e.target 将返回输入,而不是您单击的元素。此解决方案行不通。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-10
    • 1970-01-01
    • 1970-01-01
    • 2023-03-27
    • 1970-01-01
    • 2013-05-12
    • 1970-01-01
    相关资源
    最近更新 更多