草庐IT

javascript - setTimeout、jQuery 操作、transitionend 随机执行/触发

coder 2025-01-11 原文

编辑:所以现在它不是随机的,看起来它总是无法从 .css() 方法执行(未进行任何更改)。仍然不要理解我可能犯的错误。


我正在尝试使用 jQuery 和 animate.css 为删除一个 div 设置动画。

问题是这个动画依赖于随机执行的事件和操作。

此代码在 .on("click"... 处理程序中响应 click 运行:

$('section').on('click', 'button', function() {
  // Remove the selected card
  $(this).closest('.mdl-card')
    .addClass('animated zoomOut')
    .one('animationend', function() {
      empty_space = $('<div id="empty-space"></div>');
      empty_space.css('height', ($(this).outerHeight(true)));
      $(this).replaceWith(empty_space);
    });
  // everything is okay until now
  // setTimeOut() doesn't always execute
  setTimeout(function() {
    console.log("test1");
    // the following doesn't always happen...
    $('#empty-space')
      .css({
        'height': '0',
        'transition': 'height .3s'
          // transitionend doesn't always fire either
      })
      .one('transitionend', function() {
        $('#empty-space').remove();
        console.log("test2");
      });
  }, 300);
  // Upgrade the DOM for MDL
  componentHandler.upgradeDom();
});
/* Animate.css customization  */

.animated {
  animation-duration: .3s
}
<head>
  <link href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.5.2/animate.min.css" rel="stylesheet" />
  <link href="https://code.getmdl.io/1.3.0/material.indigo-pink.min.css" rel="stylesheet" />
</head>

<body>
  <section>
    <div class="mdl-card">
      <button class="mdl-button mdl-js-button">Close</button>
    </div>
    <p>
      Content to test the height of the div above
    </p>
  </section>
  <script src="https://code.getmdl.io/1.3.0/material.min.js"></script>
  <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
</body>

根据页面加载,什么也没有发生,有时只有第一个日志,有时只到 CSS 转换,有时就完成了。

在 Firefox 和 Chromium 上测试。

我可能误解了一些东西,因为它看起来真的很奇怪。

最佳答案

即使您为 setTimeout 和动画提供相同的持续时间值,它们的回调的执行顺序实际上并不能保证。 简化的原因如下:

JS 本质上是单线程的,这意味着它一次可以执行一件事情。它有一个事件循环,有一堆事件队列,所有事件队列都接受网络请求、dom 事件、动画事件等事件的回调,并且在所有这些事件中,一次只运行一个并运行到结束(Run To Completion Semantic ).由于这种单线程性,进一步的复杂性是重绘和垃圾收集之类的事情也可能在此线程上运行,因此可能会发生额外的不可预测的延迟。

有用的资源:

这意味着,虽然您将空元素的高度过渡延迟到父元素缩小之后,但由于上述因素,无法始终保证此延迟的持续时间。因此,当 setTimeout 中的回调被调用时,空元素可能不存在。

如果将 setTimeout 的延迟增加到一个更大的值,空元素的高度动画实际上会更频繁地发生,因为这会增加 zoomOut<> 动画结束和代码在 setTimeout 开始,这意味着空元素很可能在我们开始转换它的高度之前就在 DOM 中。

但是,并没有真正保证确定此延迟的最小 值的方法,因为每次都可能不同。

您必须以这样一种方式编写代码,即 animationendsetTimeout 回调的执行顺序无关紧要。


解决方案

首先,您不需要额外的空白空间,您可以在同一个元素上同时执行 zoomOut 动画和高度过渡。

您必须注意的一件事是,您正在使用的 css 库已经将 .mdl-cardmin-height 设置为某个值( 200px),所以你必须根据这个属性进行转换,因为元素的高度可能小于这个值。您还希望在 height 本身上进行转换,这样您就可以在没有任何卡顿的情况下删除元素。最后,您必须在动画和过渡完成后延迟元素的移除。

这是一个可行的解决方案:

$('section').on('click', 'button', function() {

  var isAnimationDone = false,
    isTransitionDone = false;

  var $item = $(this).closest('.mdl-card');

  $item
    .addClass('animated zoomOut')
    .one('animationend', function() {
      isAnimationDone = true;
      onAllDone();
    });

  $item
    .css({
      height: 0,
      'min-height': 0
    })
    .one('transitionend', function() {
      isTransitionDone = true;
      onAllDone();
    });

  function onAllDone() {
    if (isAnimationDone && isTransitionDone) {
        $item.remove();
    }
  }
});
.animated {
  animation-duration: 300ms
}
.mdl-card {
  transition: min-height 300ms, height 300ms;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.5.2/animate.min.css" rel="stylesheet" />
<link href="https://code.getmdl.io/1.3.0/material.indigo-pink.min.css" rel="stylesheet" />

<script src="https://code.getmdl.io/1.3.0/material.min.js"></script>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>

<section>
  <div class="mdl-card">
    <button class="mdl-button mdl-js-button">Close</button>
  </div>
  <p>
    Content to test the height of the div above
  </p>
</section>

有了 Promise,这会变得更容易一些:

function animate($item, animClass) {
  return new Promise((resolve) => {
    $item.addClass(`animated ${animClass}`).one('animationend', resolve);
  });
}

function transition($item, props) {
  return new Promise((resolve) => {
    $item.css(props).one('transitionend', resolve);
  });
}

$('section').on('click', 'button', function() {

  const $item = $(this).closest('.mdl-card');

  // start animation and transition simultaneously
  const zoomInAnimation = animate($item, 'zoomOut');
  const heightTransition = transition($item, {
    height: 0,
    'min-height': 0
  });

  // remove element once both animation and transition are finished
  Promise.all([
    zoomInAnimation,
    heightTransition
  ]).then(() => $item.remove());
});
.animated {
  animation-duration: 300ms
}
.mdl-card {
  transition: min-height 300ms, height 300ms;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.5.2/animate.min.css" rel="stylesheet" />
<link href="https://code.getmdl.io/1.3.0/material.indigo-pink.min.css" rel="stylesheet" />

<script src="https://code.getmdl.io/1.3.0/material.min.js"></script>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>

<section>
  <div class="mdl-card">
    <button class="mdl-button mdl-js-button">Close</button>
  </div>
  <p>
    Content to test the height of the div above
  </p>
</section>

关于javascript - setTimeout、jQuery 操作、transitionend 随机执行/触发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41508826/

有关javascript - setTimeout、jQuery 操作、transitionend 随机执行/触发的更多相关文章

  1. ruby-openid:执行发现时未设置@socket - 2

    我在使用omniauth/openid时遇到了一些麻烦。在尝试进行身份验证时,我在日志中发现了这一点:OpenID::FetchingError:Errorfetchinghttps://www.google.com/accounts/o8/.well-known/host-meta?hd=profiles.google.com%2Fmy_username:undefinedmethod`io'fornil:NilClass重要的是undefinedmethodio'fornil:NilClass来自openid/fetchers.rb,在下面的代码片段中:moduleNetclass

  2. ruby - Chef 执行非顺序配方 - 2

    我遵循了教程http://gettingstartedwithchef.com/,第1章。我的运行list是"run_list":["recipe[apt]","recipe[phpap]"]我的phpapRecipe默认Recipeinclude_recipe"apache2"include_recipe"build-essential"include_recipe"openssl"include_recipe"mysql::client"include_recipe"mysql::server"include_recipe"php"include_recipe"php::modul

  3. ruby - 触发器 ruby​​ 中 3 点范围运算符和 2 点范围运算符的区别 - 2

    请帮助我理解范围运算符...和..之间的区别,作为Ruby中使用的“触发器”。这是PragmaticProgrammersguidetoRuby中的一个示例:a=(11..20).collect{|i|(i%4==0)..(i%3==0)?i:nil}返回:[nil,12,nil,nil,nil,16,17,18,nil,20]还有:a=(11..20).collect{|i|(i%4==0)...(i%3==0)?i:nil}返回:[nil,12,13,14,15,16,17,18,nil,20] 最佳答案 触发器(又名f/f)是

  4. ruby-on-rails - Rails - 乐观锁定总是触发 StaleObjectError 异常 - 2

    我正在学习Rails,并阅读了关于乐观锁的内容。我已将类型为integer的lock_version列添加到我的articles表中。但现在每当我第一次尝试更新记录时,我都会收到StaleObjectError异常。这是我的迁移:classAddLockVersionToArticle当我尝试通过Rails控制台更新文章时:article=Article.first=>#我这样做:article.title="newtitle"article.save我明白了:(0.3ms)begintransaction(0.3ms)UPDATE"articles"SET"title"='dwdwd

  5. ruby-on-rails - 如何在 Rails Controller Action 上触发 Facebook 像素 - 2

    我有一个ruby​​onrails应用程序。我按照facebook的说明添加了一个像素。但是,要跟踪转化,Facebook要求您将页面置于达到预期结果时出现的转化中。即,如果我想显示客户已注册,我会将您注册后转到的页面作为成功对象进行跟踪。我的问题是,当客户注册时,在我的应用程序中没有登陆页面。该应用程序将用户带回主页。它在主页上显示了一条消息,所以我想看看是否有一种方法可以跟踪来自Controller操作而不是实际页面的转化。我需要计数的Action没有页面,它们是ControllerAction。是否有任何人都知道的关于如何执行此操作的gem、文档或最佳实践?这是进入布局文件的像素

  6. ruby - 为什么 Ruby 的 each 迭代器先执行? - 2

    我在用Ruby执行简单任务时遇到了一件奇怪的事情。我只想用每个方法迭代字母表,但迭代在执行中先进行:alfawit=("a".."z")puts"That'sanalphabet:\n\n#{alfawit.each{|litera|putslitera}}"这段代码的结果是:(缩写)abc⋮xyzThat'sanalphabet:a..z知道为什么它会这样工作或者我做错了什么吗?提前致谢。 最佳答案 因为您的each调用被插入到在固定字符串之前执行的字符串文字中。此外,each返回一个Enumerable,实际上您甚至打印它。试试

  7. jquery - 我的 jquery AJAX POST 请求无需发送 Authenticity Token (Rails) - 2

    rails中是否有任何规定允许站点的所有AJAXPOST请求在没有authenticity_token的情况下通过?我有一个调用Controller方法的JqueryPOSTajax调用,但我没有在其中放置任何真实性代码,但调用成功。我的ApplicationController确实有'request_forgery_protection'并且我已经改变了config.action_controller.consider_all_requests_local在我的environments/development.rb中为false我还搜索了我的代码以确保我没有重载ajaxSend来发送

  8. ruby - 检查是否通过 require 执行或导入了 Ruby 程序 - 2

    如何检查Ruby文件是否是通过“require”或“load”导入的,而不是简单地从命令行执行的?例如:foo.rb的内容:puts"Hello"bar.rb的内容require'foo'输出:$./foo.rbHello$./bar.rbHello基本上,我想调用bar.rb以不执行puts调用。 最佳答案 将foo.rb改为:if__FILE__==$0puts"Hello"end检查__FILE__-当前ruby​​文件的名称-与$0-正在运行的脚本的名称。 关于ruby-检查是否

  9. 华为OD机试用Python实现 -【明明的随机数】 2023Q1A - 2

    华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o

  10. postman——集合——执行集合——测试脚本——pm对象简单示例02 - 2

    //1.验证返回状态码是否是200pm.test("Statuscodeis200",function(){pm.response.to.have.status(200);});//2.验证返回body内是否含有某个值pm.test("Bodymatchesstring",function(){pm.expect(pm.response.text()).to.include("string_you_want_to_search");});//3.验证某个返回值是否是100pm.test("Yourtestname",function(){varjsonData=pm.response.json

随机推荐