问题 不同浏览器中模糊事件的不同行为


考虑这个例子 我有2个输入字段:

<input id="a" />
<input id="b" style="display: none" />

并考虑以下JavaScript,这是尝试这样做:

显示 #b 只有当 #a 有焦点和隐藏 #b 每当 #a 失去焦点,除非 #a 失去了它的焦点 #b

$("#a").focus(function() {
    $("#b").show();
});

$("#a, #b").blur(function() {
    $("#b").hide();
});

$("#b").focus(function(){
    $("#b").show();
});

$("#a").focus(function() {
  $("#b").show();
});

$("#a, #b").blur(function() {
  $("#b").hide();
});

$("#b").focus(function() {
  $("#b").show();
});
#b {
  display: none;
}
<input id="a" value=a>
<input id="b" value=b>
<br/>^ focus on the input

5518
2017-07-08 15:15


起源

嗯,有趣。在这两种情况下,当然, blur 事件必须在之前解雇 focus 一。与Chrome有什么不同 focus 上 #b 仍在注册 - 开火 #b.show()。 - raina77ow
那么,那里实际上有三种不同的行为。在Chrome中,我们将光标放入 b, blur on a 然后先被解雇 focus on b; b 保持可见。在Firefox中, focus on b 没被解雇 b变得无形。然而,在IE10中,不知何故 focus on b 被解雇了,但是 b 立刻变得隐形,如 blur 被解雇了 b 之后。去搞清楚。 - raina77ow
这里的 小提琴 所有控制台输出。 - raina77ow
这里的 讨论 这似乎是相关的。注意那里有两个(略微)连接的问题。简而言之,它似乎是另一个不清楚的规范,在浏览器中实现不同。 - raina77ow
从那里开始:'在Gecko, display:none 元素不会收到关键事件'。 - raina77ow


答案:


如您所知,问题是不同的浏览器选择以不同的顺序调用事件处理程序。一种解决方案是通过设置计时器为其他事件提供触发机会 0 毫秒,然后检查字段以查看哪些(如果有)聚焦。

a.onfocus = function() {show(b);};

a.onblur = function() {
    setTimeout(function() {
        //if neither filed is focused
        if(document.activeElement !== b && document.activeElement !== a){
            hide(b);
        }
            }, 0);
};

//same action as for a
b.onblur = a.onblur;

在Chrome,Firefox,Internet Explorer和Safari中测试过。查看完整的工作示例(小提琴的编辑版本) JSFiddle.net


9
2017-07-11 10:11



setTimeout(function(){})类似于下一个tick,是一个非常糟糕的实践,用于控制程序代码(如果没有按目的完成,例如,给程序一个呼吸来执行下一个排队任务)。只是尝试在FOR循环中多次调用blur / unblur(假设为1000),你会发现异步行为会破坏你的代码流 - igorpavlov
我同意 - 问题是程序 不 需要一口气来执行下一个排队的任务,这是允许的 b 要关注的元素。是否有更好的Java相当于 Thread.yield()? - Nateowami


在隐藏b之前,您可以使用extravarible来检查b是否聚焦。它适用于IE,Chrome和Firefox。我没有任何其他浏览器。你可以检查一下。

var focusedB = false;
$("#a").focus(function(){
     $("#b").show();   
 });
 //if b is focused by pressing tab bar.
 $("#a").keydown(function(e){
     if(e.which === 9){
          focusedB = true;  
      }
   });
   $("#b").blur(function(){
        $("#b").hide();
   });
   $("#a").blur(function(){
       if(focusedB){
            focusedB = false;
        }else{
            $("#b").hide();
        }
    });
    $( "#b" ).mousedown(function() {
       focusedB = true;
    });

4
2017-07-12 10:41



这里的真正区别不在于jQuery调用的额外变量 mousedown 之前的事件 blur 事件,即使在Firefox中。加 console.log() 你会看到这种情况。 - Nateowami
我认为我们无法改变特定浏览器中的事件顺序,但正如John所说$(“#b”)。focus()永远不会被触发,因为一旦#a失去焦点,#b就会被隐藏。但是在这里我已经在模糊之前进行了mousedown事件,因此我正在使用额外的变量来检查是否隐藏b。它在Firefox中运行良好。 - Indra


根据 whatwg.org的这个档案

一个元素是 可聚焦 如果用户代理的默认行为允许   它是可聚焦的,或者如果元素是专门可聚焦的,但仅限于   如果元素正在渲染或是画布的后代   表示嵌入内容的元素。

似乎所有的浏览器也没有 visibility:hidden 和 display:none 输入元素可调焦。 以下JavaScript 案例是一个可以关注的元素的测试。

function isFocusable(type) {
    var element = document.getElementById(type);
    result += type + ' is';
    try {
        element.focus();
        if (element != document.activeElement)
            result += ' not';
    } catch (e) {
      result += ' not (error thrown)';
    }
    result += ' focusable<br>';
}

var result = '';

function isFocusable(type) {
  var element = document.getElementById(type);
  result += type + ' is';
  try {
    element.focus();
    if (element != document.activeElement)
      result += ' not';
  } catch (e) {
    result += ' not (error thrown)';
  }
  result += ' focusable<br>';
}

isFocusable('text');
isFocusable('hidden');
isFocusable('disabled');
isFocusable('readonly');
isFocusable('visiblity-hidden');
isFocusable('display-none');
isFocusable('div-hidden');

document.getElementById('browser-version').innerHTML = navigator.userAgent;
document.getElementById('logger').innerHTML += result;
<input id=text type=""></input>
<input id=hidden type="hidden"></input>
<input id=disabled disabled></input>
<input id=readonly readonly></input>
<input id=visiblity-hidden style="visibility:hidden"></input>
<input id=display-none style="display:none"></input>
<div id=div-hidden sytle="visibility:hidden" tabindex=1>
  </input>

  <div id=browser-version></div>

  <div id=logger></div>

这是Firefox 34.0.5和Chrome 39.0.2的输出

Gecko/20100101 Firefox/34.0
text is focusable
hidden is not focusable
disabled is not focusable
readonly is focusable
visiblity-hidden is not focusable
display-none is not focusable
div-hidden is focusable

AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36
text is focusable
hidden is not focusable
disabled is not focusable
readonly is focusable
visiblity-hidden is not focusable
display-none is not focusable
div-hidden is focusable

0
2017-12-18 21:14