如何在不使用setTimeout的情况下恰好在1秒后停止关键帧动画? -队列中的问题事件

时间:2018-09-07 00:52:56

标签: javascript css css3 css-animations settimeout

我认为这将是一个很难解决的问题...

我创建了一个速度计,用于显示我所在城市发生的地震的数量。 我想以两种方式为该速度表设置动画: background-color(无地震时为绿色,而 3000 地震时为红色)和此彩色div的宽度(我为背景颜色设置动画的div)。 因此,当没有地震时,宽度将为 0 ,而在发生3000次地震时,宽度将为100%。

动画是2秒,所以例如如果我有 1500 地震: 添加动画速度表类

  $('#first').addClass('first-start');

然后使用setTimeout添加一个类,以在1秒后停止动画

 setTimeout(function() {
   $('#first').addClass('first-pause');
 }, 1000);

此代码几乎总是可以正常工作。

现在我添加一个代码段:

$('#first').addClass('first-start');

setTimeout(function() {
  $('#first').addClass('first-pause');
}, 1000);
#page {
  margin-top: 50px;
  width: 300px;
  height: 300px;
  background-color: #000;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  z-index: 4;
  overflow: hidden;
}

#box-first{
  width: 200px;
  height: 100px;
  background-color: #fff;
  border-radius: 200px 200px 0 0;
  margin-top: 10px;
  margin-bottom: 10px;
  position: relative;
  display: flex;
  justify-content: flex-end;
  align-items: flex-start;
  z-index: 3;
  overflow: hidden;
}

#first{
  border-radius: 200px 200px 0 0;
  margin: 0;
  background: red;
  width: 200px;
  height: 100px;
  transform: rotate(180deg);
  transform-origin: 50% 100%;
  position: absolute;
  top: 0px;
  right: 0px;
  border: 0;
  z-index: 1;
}

#n1{
  font-size: 20px;
  color: #fff;
  font-weight: bold;
  position: absolute;
  left: 50px;
  right: 0;
  text-align: center;
  top: 50px;
  bottom: 0;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  width: 100px;
  height: 50px;
  background: #000;
  border-radius: 100px 100px 0 0;
  z-Index: 1;
  overflow: hidden;
}

@keyframes first {
  0% {
    background-color: green;
    transform: rotate(180deg);
  }
  33% {
    background-color: yellow;
    transform: rotate(240deg);
  }
  66% {
    background-color: orange;
    transform: rotate(300deg);
  }
  100% {
    background-color: red;
    transform: rotate(360deg);
  }
}



.first-start {
  animation: first 2s linear;
}

.first-pause {
  animation-play-state: paused;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="page">
  <div id="box-first">
    <div id="first">

    </div>
    <div id="n1">
      1500
    </div>
  </div> 
</div>

https://jsfiddle.net/hoymds97/

问题是我在一个包含大量事件的大文件(4000行)中使用此代码,并且在同一功能中有8个里程表。 我注意到有时(当有更多事件发生时)setTimeout不会在为动画速度计添加类后立即开始。

因此,动画将在...之后停止 例如,在我们的情况下,它好像在1700毫秒之后而不是1000秒之后被阻塞。有时甚至在2秒后也会停止。

我认为问题在于queue中的许多事件。

那我该如何解决这个问题呢?

是否可以始终使用setTimeout来解决?

希望您能帮助我,对不起我的英语。

1 个答案:

答案 0 :(得分:2)

这是一个全新的想法,它依赖于过渡而不是动画,您可以在其中轻松调整状态而不会出现同步问题。

主要技巧是为背景色使用渐变并调整其位置,以便获得所需的颜色。

以下是说明颜色的简单代码:

.box {
  background: linear-gradient(to right, green, yellow, orange, red);
  background-size: 2000% 100%;
  transition:1s;
  background-repeat: no-repeat;
  background-position: 0 0;
  height: 200px;
}

.box:hover {
  background-position: 100% 0;
}
<div class="box">

</div>

如您所见,我定义了4种颜色的渐变,我们只需要调整background-size即可获得着色({0%代表绿色,100%代表红色)。这在视觉上不会完全一样,因为我们不会像动画那样具有纯色,因此,我将background-size的大小做成了足以产生纯色错觉的地方。

现在,我们只需要找到background-positiondegree的值就很容易了。 backround-position0%100%之间的值,度是180deg360deg之间的值。对于状态50%,我们将在逻辑上将50%用于背景位置,将270deg用于变换,对于x%状态,我们将分别使用x%和{ x%*(360deg - 180deg) + 180deg = x%*180deg + 180deg = 180deg(x% + 1)

以下是50%的示例(悬停查看)

#page {
  margin-top: 50px;
  width: 300px;
  height: 300px;
  background-color: #000;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  z-index: 4;
  overflow: hidden;
}

#box-first{
  width: 200px;
  height: 100px;
  background-color: #fff;
  border-radius: 200px 200px 0 0;
  margin-top: 10px;
  margin-bottom: 10px;
  position: relative;
  display: flex;
  justify-content: flex-end;
  align-items: flex-start;
  z-index: 3;
  overflow: hidden;
}

#first{
  border-radius: 200px 200px 0 0;
  margin: 0;
  background: linear-gradient(to right, green, yellow, orange, red);
  background-size: 2000% 100%;
  background-repeat:no-repeat;
  background-position:0% 0%;
  transition:1s;
  width: 200px;
  height: 100px;
  transform: rotate(180deg);
  transform-origin: 50% 100%;
  position: absolute;
  top: 0px;
  right: 0px;
  border: 0;
  z-index: 1;
}
#box-first:hover #first{
  transform: rotate(270deg);
  background-position:50% 0%;
}

#n1{
  font-size: 20px;
  color: #fff;
  font-weight: bold;
  position: absolute;
  left: 50px;
  right: 0;
  text-align: center;
  top: 50px;
  bottom: 0;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  width: 100px;
  height: 50px;
  background: #000;
  border-radius: 100px 100px 0 0;
  z-Index: 1;
  overflow: hidden;
}
<div id="page">
  <div id="box-first">
    <div id="first">

    </div>
    <div id="n1">
      1500
    </div>
  </div> 
</div>

为了使其动态化,我们需要使用JS调整值,然后过渡就可以了。为此,我们可以为要转换为所需值的状态定义一个data-attribute

在此示例中,我还简化了html并使用了伪元素和CSS变量

setTimeout(function() {
  $('.box').each(function() {
    var d = $(this).data('state');
    $(this).attr("style", "--s:" + d);
  });
}, 1000);
body {
  margin: 0;
  background: #000;
}

.box {
  width: 200px;
  height: 100px;
  background-color: #fff;
  border-radius: 200px 200px 0 0;
  margin: 10px;
  position: relative;
  display: inline-flex;
  z-index: 0;
  overflow: hidden;
}

.box:before {
  content: "";
  position: absolute;
  z-index: -1;
  border-radius: 200px 200px 0 0;
  background: linear-gradient(to right, green, yellow, orange, red);
  background-size: 2000% 100%;
  background-repeat: no-repeat;
  background-position: calc(var(--s, 0) * 1%) 0%;
  transition:2s linear;
  width: 200px;
  height: 100px;
  transform: rotate(calc((var(--s, 0)/100 + 1)*180deg));
  transform-origin: 50% 100%;
  top: 0px;
  right: 0px;
}

.box:after {
  content: attr(data-number);
  font-size: 20px;
  color: #fff;
  font-weight: bold;
  text-align: center;
  margin: auto auto 0;
  width: 100px;
  height: 50px;
  line-height: 50px;
  background: #000;
  border-radius: 100px 100px 0 0;
  z-Index: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box" data-number="1500" data-state="50"></div>

<div class="box" data-number="1000" data-state="20"></div>

<div class="box" data-number="3000" data-state="80"></div>

<div class="box" data-number="6000" data-state="100"></div>

您可能会注意到,所有人的时长相同,因为所有人的过渡时间都相同。如果您希望使用不同的持续时间并保持相同的速度,只需在过渡中使用CSS变量即可。

setTimeout(function() {
  $('.box').each(function() {
    var d = $(this).data('state');
    $(this).attr("style", "--s:" + d);
  });
}, 1000);
body {
  margin: 0;
  background: #000;
}

.box {
  width: 200px;
  height: 100px;
  background-color: #fff;
  border-radius: 200px 200px 0 0;
  margin: 10px;
  position: relative;
  display: inline-flex;
  z-index: 0;
  overflow: hidden;
}

.box:before {
  content: "";
  position: absolute;
  z-index: -1;
  border-radius: 200px 200px 0 0;
  background: linear-gradient(to right, green, yellow, orange, red);
  background-size: 2000% 100%;
  background-repeat: no-repeat;
  background-position: calc(var(--s, 0) * 1%) 0%;
  transition: calc(2s * var(--s, 0)/100) linear;
  width: 200px;
  height: 100px;
  transform: rotate(calc((var(--s, 0)/100 + 1)*180deg));
  transform-origin: 50% 100%;
  top: 0px;
  right: 0px;
}

.box:after {
  content: attr(data-number);
  font-size: 20px;
  color: #fff;
  font-weight: bold;
  text-align: center;
  margin: auto auto 0;
  width: 100px;
  height: 50px;
  line-height: 50px;
  background: #000;
  border-radius: 100px 100px 0 0;
  z-Index: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box" data-number="1500" data-state="50"></div>

<div class="box" data-number="1000" data-state="20"></div>

<div class="box" data-number="3000" data-state="80"></div>

<div class="box" data-number="6000" data-state="100"></div>