1

我正在尝试为一些应该从右侧进入屏幕的卡片设置动画,在中间停一会儿,然后在无限循环中消失到左侧。这是我尝试过的:

function startAnimation(elem) {
  $('#' + elem).fadeIn(150).animate({
    left: '0'
  }, 1500);
}

function endAnimation(elem) {
  $('#' + elem).animate({
    left: '-200%'
  }, 1500);

  $('#' + elem).fadeOut(100).animate({
    left: '200%'
  }, 300);
}

function scrollCards(elem, n) {
  startAnimation(elem);

  setTimeout(function() {
    endAnimation(elem);
  }, 700);

  elem += 1;
  elem = elem == n ? 0 : elem;
  return elem;
}

n = 3;
var card = 0
var firstAnimationDone = false;
$('#0').fadeIn(150);

setInterval(function() {
  if (!firstAnimationDone) {
    endAnimation(card);
    card = 1;
  }
  card = scrollCards(card, n);
  firstAnimationDone = true;
}, 4500);
/* (boxArticle is here just to keep static the part of the page where the animation takes place) */

.boxArticle {
  overflow: hidden;
  height: 100px;
}

.boxAchievements {
  position: relative;
  height: 100px;
  width: 100%;
  left: 200%;
  top: 5px;
  display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="boxArticle">
  <article class="boxAchievements" id="0">
    <h2>My achievements</h2>
    <p>Write 1</p>
  </article>
  <article class="boxAchievements" id="1">
    <h2>My achievements</h2>
    <p>Write 2</p>
  </article>
  <article class="boxAchievements" id="2">
    <h2>My achievements</h2>
    <p>Write 3</p>
  </article>
</div>

当我添加setTimeoutscrollCards函数时,它会在中间停很长时间,无论我在方法中放置的间隔有多长,它都会使循环不同步,所以我有 2 张卡同时移动。

4

1 回答 1

0

您可以改用 CSSanimation规则,用更少的代码实现您想要的。下面的解决方案使用了一种技巧,可以使无限动画在迭代之间延迟运行(例如,请参阅此 Q&A)。

简而言之,动画时长的设置是考虑@keyframes到延迟的,通过从某个点到100%保持相同的动画属性值来控制延迟(即如果需要2s,而延迟为8s,则将时长设置为8+2 =10s,完成属性变化100*2/10=20%)。

然后,您可以随时添加该类animation。要对齐动画,请按顺序添加类,步长等于:持续时间 + 延迟 / 元素数。

请注意,<article>由于删除了fadeIn/fadeOut方法调用和display: none;规则,您的 CSS 已更改为正确对齐元素。

(() => {

  $('#0').addClass("middle");
  
  setTimeout(() => $("#1").addClass("middle"), 5e3);
  
  setTimeout(() => $("#2").addClass("middle"), 9e3);
  
})();
body {
  margin: 0;
}

:root {
  --middle : calc(50% - 25vw / 2);
  --left   : calc(0% - 25vw);
  
  --duration : 12s;
}

.boxArticle {
  position: relative;
  overflow: hidden;
  height: 100vh;
  width: 100vw;
}

.boxAchievements {
  position: absolute;
  height: 100px;
  width: 25vw;
  left: 200%;
  top: 5px;
}

.middle {
  animation: 
    middle var(--duration) linear 0s normal infinite forwards running,
    left   var(--duration) linear 0s normal infinite forwards running;
}

@keyframes middle {
  8.3%, 100% { left: var(--middle); }
}

@keyframes left {
  8.3%, 24.9% { left: var(--middle); }
  33.2%, 100%  { left: var(--left); }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="boxArticle">
  <article class="boxAchievements" id="0">
    <h2>My achievements</h2>
    <p>Write 1</p>
  </article>
  <article class="boxAchievements" id="1">
    <h2>My achievements</h2>
    <p>Write 2</p>
  </article>
  <article class="boxAchievements" id="2">
    <h2>My achievements</h2>
    <p>Write 3</p>
  </article>
</div>


您的代码段中还有一些关于代码的注释:

  1. 不要混合变量类型。尽管 JavaScript 允许这样做,但对于任何将阅读您的代码的人(包括一年后的您)来说,这都是噩梦的来源。特别是,scrollCards有一个参数elem应该是 a Element,而不是 a number(反之亦然)。

  2. 使用递归 setTimeout而不是setInterval- 后者将函数调用排队,无论前一个动画是否完成(还有其他原因使用递归setTimeout,超出了问题范围)。

  3. 声明nvar更好的是 - 不要声明任何全局变量,但至少避免通过省略声明关键字来创建隐含的全局变量)。

  4. setTimeout由于调用是异步的,因此不能保证在指定的时间后运行调用 - 根据页面加载,动画完全不同步的风险会随着时间的推移而增加。

    缓解这种情况的一种方法是使用 Promise 等到超时触发,但是将项目动画与之对齐可能是一项艰巨的任务。例如,以下是您如何scrollCards等待endAnimation发生:

(() => {
  const now = () => new Date().toISOString();
  const startAnimation = (elem) => console.log(`started animation at ${now()}`);
  const endAnimation = (elem) => console.log(`ended animation at ${now()}`);
  
  async function scrollCards(elem, n) {
    startAnimation(elem);

    //assuming endAnimation is synchronous
    await new Promise((resolve) => setTimeout((elem) => resolve(endAnimation(elem)), 700, elem));

    elem += 1; //see #1 - this is error-prone
    elem = elem == n ? 0 : elem;
    return elem;
  };
    
  scrollCards(0,1);
})();

于 2021-02-08T18:59:19.643 回答