js confirm()/ Firefox vs Chrome行为之后的focus()事件

时间:2017-08-24 20:52:40

标签: javascript jquery google-chrome firefox

我有一个复杂的Web应用程序,它部分依赖于focus()事件,而且在函数中使用confirm()框时遇到了一些困难。

似乎退出确认框会在关闭时触发focus()事件,但Firefox中的行为与Chrome中的行为不同。为什么?至少,我需要找到一种方法,使这些事件在浏览器中保持一致。

我把下面的示例放在一起,说明了我的意思。

如果您确认Firefox(v55.0.2)中的方框,您将在初始focus()框中触发<input>事件,然后该功能将触发第二个focus()目标元素上的事件(下一个<input>元素)。

相比之下,如果您在Chrome(v60.0.3112.101)中执行相同操作,则会在下一个上触发两个 focus()个事件> <input>元素 - 一个来自函数,一个来自可能来自确认对话框。

编辑:在Chrome v49.0.2623.112上进行了测试,并且只有一个 focus()事件(由我的函数明确触发的事件),这就是我所说的当我第一次开发应用程序时,期望和事情表现得很好。现在真的很困惑,因为各种浏览器有三种不同的方式来处理退出confirm()对话框。

$('form').on('keypress', 'input', function(e) {
  if (e.keyCode == 13) {
    validate(this);
  }
});
$('form').on('focus', 'input[type=text]', function() {
  var n = +$(this).next('span').text();
  n++;
  $(this).next('span').text(n);
});

function validate(self) {
  var next = $(self).closest('div').nextAll('div').first();
  if (confirm('Are you sure?')) {
    next.find('input[type=text]').prop('disabled', false).focus();
  }

}
div {
  margin: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<h2>Type some text and hit return:</h2>
<form>
  <div><input autocomplete="off" type="text"> Focus Events: <span class="info">0</span></div>
  <div><input autocomplete="off" disabled type="text"> Focus Events: <span class="info">0</span></div>
  <div><input autocomplete="off" disabled type="text"> Focus Events: <span class="info">0</span></div>
  <div><input autocomplete="off" disabled type="text"> Focus Events: <span class="info">0</span></div>
</form>

2 个答案:

答案 0 :(得分:2)

总结一下您的问题,您面临的问题是:

  • Firefox在确认时触发当前和下一个输入元素上的焦点事件
  • Chrome在下一个输入元素上触发焦点事件两次(事实上,我也可以在OS X Safari中重现这一点,可能是因为Blink和Webkit曾经属于同一个分支)

虽然我无法确认浏览器的内部工作原理,但似乎他们的JS引擎有不同的解决竞争条件的方法。基本上,当用户存在应用级模式(警报,确认等)时,输入元素将“重新聚焦”,但不同的浏览器引擎决定何时触发焦点事件。

如果你想强制两个浏览器在下一个元素上触发焦点事件并重复删除它,你可以简单地在callstack结束时执行焦点,即:

var next = $(self).closest('div').nextAll('div').first(),
    nextInput = next.find('input[type=text]');

if (confirm('Are you sure?')) {
    // Remove disabled prop
    nextInput.prop('disabled', false);

    // Focus at end of callstack
    window.setTimeout(function() {
        nextInput.focus();
    }, 0);
}

请参阅下面的概念验证示例:

$('form').on('keypress', 'input', function(e) {
  if (e.keyCode == 13) {
    validate(this);
  }
});
$('form').on('focus', 'input[type=text]', function() {
  var n = +$(this).next('span').text();
  n++;
  $(this).next('span').text(n);
});

function validate(self) {
  var next = $(self).closest('div').nextAll('div').first(),
      nextInput = next.find('input[type=text]');
      
  if (confirm('Are you sure?')) {
    // Remove disabled prop
    nextInput.prop('disabled', false);
    
    // Focus at end of callstack
    window.setTimeout(function() {
      nextInput.focus();
    }, 0);
  }

}
div {
  margin: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<h2>Type some text and hit return:</h2>
<form>
  <div><input autocomplete="off" type="text"> Focus Events: <span class="info">0</span></div>
  <div><input autocomplete="off" disabled type="text"> Focus Events: <span class="info">0</span></div>
  <div><input autocomplete="off" disabled type="text"> Focus Events: <span class="info">0</span></div>
  <div><input autocomplete="off" disabled type="text"> Focus Events: <span class="info">0</span></div>
</form>

答案 1 :(得分:1)

您可以设置一个标志以指示显示确认框,并在标志打开时忽略所有焦点事件。关闭确认框后,您可以在聚焦下一个字段之前异步重置标记(如Terry's answer中所示)。

&#13;
&#13;
var isConfirming = false;

$('form').on('keypress', 'input', function(e) {
  if (e.keyCode == 13) {
    validate(this);
  }
});
$('form').on('focus', 'input[type=text]', function() {
  // Ignore the focus events caused by the confirm box
  if (!isConfirming) {
    var n = +$(this).next('span').text();
    n++;
    $(this).next('span').text(n);
  }
});

function validate(self) {
  var next = $(self).closest('div').nextAll('div').first(),
    nextInput = next.find('input[type=text]');

  isConfirming = true; // Set the flag before showing the confirm box

  if (confirm('Are you sure?')) {
    nextInput.prop('disabled', false);

    // Reset the flag and change focus asynchronously 
    window.setTimeout(function() {
      isConfirming = false;
      nextInput.focus();
    }, 0);
  } else {
    // Reset the flag asynchronously 
    window.setTimeout(function() {
      isConfirming = false;
    }, 0);
  }
}
&#13;
div {
  margin: 10px;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<h2>Type some text and hit return:</h2>
<form>
  <div><input autocomplete="off" type="text"> Focus Events: <span class="info">0</span></div>
  <div><input autocomplete="off" disabled type="text"> Focus Events: <span class="info">0</span></div>
  <div><input autocomplete="off" disabled type="text"> Focus Events: <span class="info">0</span></div>
  <div><input autocomplete="off" disabled type="text"> Focus Events: <span class="info">0</span></div>
</form>
&#13;
&#13;
&#13;