javascript - SetTimeout 和 ScrollTop 的奇怪行为

标签 javascript jquery

我不明白为什么我必须将 scrollTop 函数包装在 setTimeout 中。我知道 setTimeout 在幕后发生了什么:将函数放入回调队列中(从 Web API 提供),并在调用堆栈中的所有代码完成时执行。但为什么在这种情况下我没有 setTimeout 就有这种行为?

例如,选择西类牙卢森堡(ctrl+单击),停留在选择选择器的底部。使用两个按钮进行测试。发生两种不同的行为。

编辑1:编辑:删除所有console.log,如果没有setTimeout仍然无法工作

编辑2:在第一个答案之后,我尝试了@Murali尼泊尔利的代码,但仍然无法工作。您可以准确地看到发生了什么(我使用的是 Google Chrome)

编辑3:仅出现在Chrome上,我的版本:75.0.3770.142(Build officiel)(64位)(同类:稳定)

scrollTop not working

$(function() {

  $('form').on('resetwithtimeout', function(e) {

    var $select = $(e.currentTarget).find('select');

    $select.find('option')
      .filter(':selected').prop("selected", false).end()
      .filter(':first').prop("selected", true);

    setTimeout(function() {
      $select.scrollTop(0);
    }, 0);

  });

  $('form').on('resetwithouttimeout', function(e) {

    var $select = $(e.currentTarget).find('select');

    $select.find('option')
      .filter(':selected').prop("selected", false).end()
      .filter(':first').prop("selected", true);

    $select.scrollTop(0);
  });

  $('#button1').on('click', function(e) {
    $('form').trigger('resetwithtimeout');
  })

  $('#button2').on('click', function(e) {
    $('form').trigger('resetwithouttimeout');
  })
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<body>
  <form>
    <select name="country" id="country-select" multiple size="5">
      <option selected value="austria">Austria</option>
      <option value="belgium">Belgium</option>
      <option value="bulgaria">Bulgaria</option>
      <option value="croatia">Croatia</option>
      <option value="republic">Republic of Cyprus</option>
      <option value="czech">Czech Republic</option>
      <option value="denmark">Denmark</option>
      <option value="estonia">Estonia</option>
      <option value="finland">Finland</option>
      <option value="france">France</option>
      <option value="germany">Germany</option>
      <option value="greece">Greece</option>
      <option value="hungary">Hungary</option>
      <option value="ireland">Ireland</option>
      <option value="italy">Italy</option>
      <option value="latvia">Latvia</option>
      <option value="lithuania">Lithuania</option>
      <option value="luxembourg">Luxembourg</option>
      <option value="malta">Malta</option>
      <option value="netherlands">Netherlands</option>
      <option value="poland">Poland</option>
      <option value="portugal">Portugal</option>
      <option value="romania">Romania</option>
      <option value="slovakia">Slovakia</option>
      <option value="slovenia">Slovenia</option>
      <option value="spain">Spain</option>
      <option value="sweden">Sweden and the UK</option>
    </select>
    <button id="button1" type="button">Reset form with scroll inside setTimeout</button>
    <button id="button2" type="button">Reset form with scroll not inside a setTimeout</button>
  </form>
</body>

谢谢!

最佳答案

这是一个 Chrome 错误。

无论出于何种原因,他们都会尝试调用 scrollIntoView 每次我们以编程方式更改其中一个

var $select = $('select')
  .on('input', function() {
    console.log('try to scroll inside the select');
    current = 0;
    this.scrollTop = 0; // move to top
    startSelect();
    $select
      .find('.user-selected').removeClass('user-selected')
      .end().find(':selected').addClass('user-selected');
  })
var $options = $select.find('option');
var current = 0;

console.log('select any option');

// selects all the <option>s one by one
function startSelect() {
  setTimeout(function() {
    $options.prop("selected", false)
      .get(current).selected = true;
    // call recursively
    if ((++current) < 26) startSelect();
  }, 1000);
}
.user-selected {
  color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>


<form>
  <select name="country" id="country-select" multiple size="5">
    <option value="austria">Austria</option>
    <option value="belgium">Belgium</option>
    <option value="bulgaria">Bulgaria</option>
    <option value="croatia">Croatia</option>
    <option value="republic">Republic of Cyprus</option>
    <option value="czech">Czech Republic</option>
    <option value="denmark">Denmark</option>
    <option value="estonia">Estonia</option>
    <option value="finland">Finland</option>
    <option value="france">France</option>
    <option value="germany">Germany</option>
    <option value="greece">Greece</option>
    <option value="hungary">Hungary</option>
    <option value="ireland">Ireland</option>
    <option value="italy">Italy</option>
    <option value="latvia">Latvia</option>
    <option value="lithuania">Lithuania</option>
    <option value="luxembourg">Luxembourg</option>
    <option value="malta">Malta</option>
    <option value="netherlands">Netherlands</option>
    <option value="poland">Poland</option>
    <option value="portugal">Portugal</option>
    <option value="romania">Romania</option>
    <option value="slovakia">Slovakia</option>
    <option value="slovenia">Slovenia</option>
    <option value="spain">Spain</option>
    <option value="sweden">Sweden and the UK</option>
  </select>
</form>

因为他们显然用 { behavior: "auto" } 来调用它选项,您甚至无法确定您的 setTimeout(fn, 0)足以对抗它。

但是对于您想要做的事情,也许 reset()

元素的方法可能适合,甚至只是 <button type="reset"> 。这些不受这种奇怪行为的影响:

var $form = $('form');
var $select = $form.find('select');
$form.on('reset', function() {
  $select.scrollTop(0);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>


<form>
  <select name="country" id="country-select" multiple size="5">
    <option selected value="austria">Austria</option>
    <option value="belgium">Belgium</option>
    <option value="bulgaria">Bulgaria</option>
    <option value="croatia">Croatia</option>
    <option value="republic">Republic of Cyprus</option>
    <option value="czech">Czech Republic</option>
    <option value="denmark">Denmark</option>
    <option value="estonia">Estonia</option>
    <option value="finland">Finland</option>
    <option value="france">France</option>
    <option value="germany">Germany</option>
    <option value="greece">Greece</option>
    <option value="hungary">Hungary</option>
    <option value="ireland">Ireland</option>
    <option value="italy">Italy</option>
    <option value="latvia">Latvia</option>
    <option value="lithuania">Lithuania</option>
    <option value="luxembourg">Luxembourg</option>
    <option value="malta">Malta</option>
    <option value="netherlands">Netherlands</option>
    <option value="poland">Poland</option>
    <option value="portugal">Portugal</option>
    <option value="romania">Romania</option>
    <option value="slovakia">Slovakia</option>
    <option value="slovenia">Slovenia</option>
    <option value="spain">Spain</option>
    <option value="sweden">Sweden and the UK</option>
  </select>
  <button type="reset">Reset form</button>
</form>

关于javascript - SetTimeout 和 ScrollTop 的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57154797/

相关文章:

javascript - Jest Mongo CI 测试

javascript - 使用零剪贴板复制文本区域

javascript - document.defaultView === 窗口循环引用?

php - 需要从从 php 转换为 jquery 的数组中按值获取索引

jquery - Rails 3嵌套模型形式创建重复的模型对象

javascript - BackboneJS 如何添加JPlayer

javascript - 如何居中 Canvas javascript?

javascript - Owl Carousel JS返回第一张图片

JQuery BlockUI 阻止消息不会立即显示

javascript - jQuery 函数在进行 ajax 调用后不起作用