最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Different behavior of blur event in different browsers - Stack Overflow

programmeradmin1浏览0评论

Consider this example where I have 2 input fields:

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

And consider the following JavaScript, which is an attempt to do this:

Show #b only when #a has focus and hide #b whenever #a loses focus, except when #a loses its focus to #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

Consider this example where I have 2 input fields:

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

And consider the following JavaScript, which is an attempt to do this:

Show #b only when #a has focus and hide #b whenever #a loses focus, except when #a loses its focus to #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

The above code is incorrect as $("#b").focus() would never be triggered because as soon as #a loses focus, #b is hidden. This expected behavior is observed in Firefox (Version 24.6.0).

But in Chrome (Version 35.0), the code seems to run incorrectly (or correctly!?).

Clearly, the b.focus event is still being registered in Chrome. Why does this event register in Chrome, but not in Firefox?


Update

As pointed out by raina77ow:

  • In Chrome, after we place the cursor on b, blur on a is fired first, then focus on b, and b stays visible.
  • In Firefox, focus on b is not fired, so b becomes invisible.
  • In IE10, however, somehow focus on b IS fired, but b becomes invisible immediately, as blur is fired on b right after.

Here's a fiddle without using jQuery, producing the same behavior.

Share Improve this question edited Sep 21, 2019 at 7:55 Brian Tompsett - 汤莱恩 5,89372 gold badges61 silver badges133 bronze badges asked Jul 8, 2014 at 15:15 John BupitJohn Bupit 10.6k9 gold badges43 silver badges79 bronze badges 5
  • Hmm, interesting. In both cases, naturally, blur Event just has to be fired before the focus one. What's different is that in Chrome focus on #b is still registered - firing up #b.show(). – raina77ow Commented Jul 8, 2014 at 15:23
  • 2 Well, there's actually three different behaviours there. In Chrome, after we place the cursor in b, blur on a is fired first, then focus on b; b stays visible. In Firefox, focus on b is not fired, b becomes invisible. In IE10, however, somehow focus on b IS fired, but b becomes invisible immediately, as blur is fired on b right after. Go figure. – raina77ow Commented Jul 8, 2014 at 15:38
  • 2 Here's fiddle with all the console outputs. – raina77ow Commented Jul 8, 2014 at 15:39
  • 2 Here's the discussion that seems to be related. Note two (slightly) connected issues in there. In short, it seems to be yet another case of unclear spec, implemented differently in browsers. – raina77ow Commented Jul 9, 2014 at 11:00
  • From the line's there: 'In Gecko, display:none elements don't receive key events'. – raina77ow Commented Jul 9, 2014 at 11:01
Add a comment  | 

3 Answers 3

Reset to default 9 +25

As you know, the issue is that different browsers choose to call event handlers in different orders. One solution is to give the other events a chance to fire by setting a timer for 0 milliseconds, and then checking the fields to see which (if any) is focused.

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;

Tested in Chrome, Firefox, Internet Explorer, and Safari. See full working example (edited version of your fiddle) at JSFiddle.net.

You can use an extravarible to check whether b is focused before hiding b. It worked in IE, Chrome & Firefox. I don;t have any other browser. You can check it.

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;
    });

According to this archive of whatwg.org:

An element is focusable if the user agent's default behavior allows it to be focusable or if the element is specially focusable, but only if the element is either being rendered or is a descendant of a canvas element that represents embedded content.

It seems that all browsers also don't make visibility:hidden and display:none input elements focusable. The following JavaScript tests in which cases is an element focusable.

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>

Here's the output in Firefox 34.0.5 and 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)

  1. 暂无评论