javascript - 如何在 Angular 中实现翻转时钟

标签 javascript html css angular angular-animations

我正在尝试使用 Angular 实现倒计时器,如 this 中实现的

问题是动画没有应用于值的更改,我缺少什么?

html

<div>
  <div class="flipclock" *ngIf="timer$ | async as timer">
    <div id="container" class="flipclock">
      <ul class="flip " *ngFor="let time of timer">
        <li
          *ngFor="let item of time.split(''); let i = index"
          [class.d1]="i === 1"
          [class.d2]="i === 0"
        >
          <section class="ready">
            <div class="up">
              <div class="shadow"></div>
              <div class="inn">{{ item }}</div>
            </div>
            <div class="down">
              <div class="shadow"></div>
              <div class="inn">{{ item }}</div>
            </div>
          </section>
          <section class="active">
            <div class="up">
              <div class="shadow"></div>
              <div class="inn">{{ item }}</div>
            </div>
            <div class="down">
              <div class="shadow"></div>
              <div class="inn">{{ item }}</div>
            </div>
          </section>
        </li>
      </ul>
    </div>
  </div>
</div>

export class AppComponent  {
  name = 'Angular ' + VERSION.major;
    initialMinutes$ = new BehaviorSubject(30);
  expired$ = new Subject();

  @Input()
  set minutes(val) {
    this.initialMinutes$.next(val);
  }

  timer$ = this.initialMinutes$.pipe(
    switchMap(minutes => timer(0, 1000).pipe(
      map(t => minutes * 60 - t),
      tap(seconds => {
        if (seconds < 0) {
          this.expired$.next();
        }
      }),
      takeUntil(this.expired$),
      map(seconds => ({
        hr: Math.max(Math.floor(seconds / 3600), 0),
        min: Math.max(Math.floor((seconds % 3600) / 60), 0),
        s: (seconds % 60)
      })),
      map(({hr, min, s}) => ([
        hr > 9 ? hr.toString() : '0' + hr.toString(),
        min > 9 ? min.toString() : '0' + min.toString(),
        s > 9 ? s.toString() : '0' + s.toString(),
      ]))
    ))
  );
}

CSS



.flipclock {
}
.flipclock hr {
  position: absolute;
  left: 0;
  top: 65px;
  width: 100%;
  height: 3px;
  border: 0;
  background: #000;
  z-index: 10;
  opacity: 0;
}
ul.flip {
  position: relative;
  float: left;
  margin: 10px;
  padding: 0;
  width: 90px;
  height: 60px;
  font-size: 60px;
  font-weight: 400;
  line-height: 60px;
}

ul.flip li {
  float: left;
  margin: 0;
  padding: 0;
  width: 49%;
  height: 100%;
  -webkit-perspective: 200px;
  list-style: none;
}

ul.flip li.d1 {
  float: right;
}

ul.flip li section {
  z-index: 1;
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;

}

ul.flip li section:first-child {
  z-index: 2;
}

ul.flip li div {
  z-index: 1;
  position: absolute;
  left: 0;
  width: 100%;
  height: 49%;
  overflow: hidden;
}

ul.flip li div .shadow {
  display: block;
  position: absolute;
  width: 100%;
  height: 100%;
  z-index: 2;
}

ul.flip li div.up {
  -webkit-transform-origin: 50% 100%;
  top: 0;
}

ul.flip li div.down {
  -webkit-transform-origin: 50% 0;
  bottom: 0;
}

ul.flip li div div.inn {
  position: absolute;
  left: 0;
  z-index: 1;
  width: 100%;
  height: 200%;
  color: #fff;
  text-shadow: 0 0 2px #fff;
  text-align: center;
  background-color: #000;
  border-radius: 6px;
}

ul.flip li div.up div.inn {
  top: 0;

}

ul.flip li div.down div.inn {
  bottom: 0;
}

/*--------------------------------------
 PLAY
--------------------------------------*/

.play ul section.ready {
  z-index: 3;
}

.play ul section.active {
  -webkit-animation: index .5s .5s linear both;
  z-index: 2;
}

@-webkit-keyframes index {
  0% {
    z-index: 2;
  }
  5% {
    z-index: 4;
  }
  100% {
    z-index: 4;
  }
}

.play ul section.active .down {
  z-index: 2;
  -webkit-animation: flipdown .5s .5s linear both;
}

@-webkit-keyframes flipdown {
  0% {
    -webkit-transform: rotateX(90deg);
  }
  80% {
    -webkit-transform: rotateX(5deg);
  }
  90% {
    -webkit-transform: rotateX(15deg);
  }
  100% {
    -webkit-transform: rotateX(0deg);
  }
}

.play ul section.ready .up {
  z-index: 2;
  -webkit-animation: flipup .5s linear both;
}

@-webkit-keyframes flipup {
  0% {
    -webkit-transform: rotateX(0deg);
  }
  90% {
    -webkit-transform: rotateX(0deg);
  }
  100% {
    -webkit-transform: rotateX(-90deg);
  }
}

/*--------------------------------------
 SHADOW
--------------------------------------*/

.play ul section.ready .up .shadow {
  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, rgba(0, 0, 0, .1)), color-stop(100%, rgba(0, 0, 0, 1)));
  background: linear-gradient(to bottom, rgba(0, 0, 0, .1) 0%, rgba(0, 0, 0, 1) 100%);
  -webkit-animation: show .5s linear both;
}

.play ul section.active .up .shadow {
  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, rgba(0, 0, 0, .1)), color-stop(100%, rgba(0, 0, 0, 1)));
  background: linear-gradient(to bottom, rgba(0, 0, 0, .1) 0%, rgba(0, 0, 0, 1) 100%);
  -webkit-animation: hide .5s .3s linear both;
}

/*DOWN*/

.play ul section.ready .down .shadow {
  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, rgba(0, 0, 0, 1)), color-stop(100%, rgba(0, 0, 0, .1)));
  background: linear-gradient(to bottom, rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, .1) 100%);
  -webkit-animation: show .5s linear both;
}

.play ul section.active .down .shadow {
  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, rgba(0, 0, 0, 1)), color-stop(100%, rgba(0, 0, 0, .1)));
  background: linear-gradient(to bottom, rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, .1) 100%);
  -webkit-animation: hide .5s .3s linear both;
}

@-webkit-keyframes show {
  0% {
    opacity: 0;
  }
  90% {
    opacity: .10;
  }
  100% {
    opacity: 1;
  }
}

@-webkit-keyframes hide {
  0% {
    opacity: 1;
  }
  80% {
    opacity: .20;
  }
  100% {
    opacity: 0;
  }
}

See this Demo on stackblitz

编辑 1

我已经设法让动画反射(reflect)出来,但它现在反射(reflect)在所有元素上

enter link description here

最佳答案

我制作了一个类似于“this”链接的计时器。(不要按图像的 fps 输出的 fps 更高)

enter image description here

这对你有用。

var h = document.getElementsByClassName('hours');

var m = document.getElementsByClassName('min');

var s = document.getElementsByClassName('sec');
var now = new Date().getTime();

var distance = now;
var hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
var minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
var seconds = Math.floor((distance % (1000 * 60)) / 1000);

var prev_sec = seconds;
var prev_min = minutes;
var prev_hour = hours;
h[0].innerHTML = h[2].innerHTML = parseInt(hours / 10);
h[1].innerHTML = h[3].innerHTML = parseInt(hours % 10);
m[0].innerHTML = m[2].innerHTML = parseInt(minutes / 10);
m[1].innerHTML = m[3].innerHTML = parseInt(minutes % 10);
s[0].innerHTML = s[2].innerHTML = parseInt(seconds / 10);
s[1].innerHTML = s[3].innerHTML = parseInt(seconds % 10);

var x = setInterval(function() {

  // Get today's date and time
  var now = new Date().getTime();

  // Find the distance between now and the count down date
  var distance = now;

  // Time calculations for days, hours, minutes and seconds



  var hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
  var minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
  var seconds = Math.floor((distance % (1000 * 60)) / 1000);



  h[0].innerHTML = h[2].innerHTML = parseInt(hours / 10);
  h[1].innerHTML = h[3].innerHTML = parseInt(hours % 10);
  m[0].innerHTML = m[2].innerHTML = parseInt(minutes / 10);
  m[1].innerHTML = m[3].innerHTML = parseInt(minutes % 10);
  s[0].innerHTML = s[2].innerHTML = parseInt(seconds / 10);
  s[1].innerHTML = s[3].innerHTML = parseInt(seconds % 10);
  h[4].innerHTML = parseInt(prev_hour / 10);
  h[5].innerHTML = parseInt(prev_hour % 10);
  m[4].innerHTML = parseInt(prev_min / 10);
  m[5].innerHTML = parseInt(prev_min % 10);
  s[4].innerHTML = parseInt(prev_sec / 10);
  s[5].innerHTML = parseInt(prev_sec % 10);


  h[2].style.animation = parseInt(prev_hour / 10) != parseInt(hours / 10) ? "reflect 1s infinite" : "stay 1s infinite";
  h[3].style.animation = parseInt(prev_hour % 10) != parseInt(hours % 10) ? "reflect 1s infinite" : "stay 1s infinite";
  m[2].style.animation = parseInt(prev_min / 10) != parseInt(minutes / 10) ? "reflect 1s infinite" : "stay 1s infinite";
  m[3].style.animation = parseInt(prev_min % 10) != parseInt(minutes % 10) ? "reflect 1s infinite" : "stay 1s infinite";
  s[2].style.animation = parseInt(prev_sec / 10) != parseInt(seconds / 10) ? "reflect 1s infinite" : "stay 1s infinite";
  s[3].style.animation = "reflect 1s infinite";


  prev_sec = seconds;
  prev_min = minutes
  prev_hour = hours;
}, 1000);
* {
  font-family: 'arial';
  font-weight: bold;
}

.main_Timer {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

.time {
  clip-path: polygon(0 0, 100% 0, 100% 50%, 0 50%);
}

.time span,
.time_reflection span,
.time_prev span {
  color: white;
  font-size: 120px;
  background-color: #252525;
  border-radius: 10px;
  padding: 5px 10px 0px 10px;
  transition: 0.4s;
  text-align: center;
  margin-right: 3px;
}

@keyframes time {
  0% {
    filter: brightness(70%);
  }
  90%,
  100% {
    filter: brightness(100%);
  }
}

.line_hor {
  position: absolute;
  background-color: white;
  width: 650px;
  height: 2px;
  margin-top: -72px;
  z-index: 10;
}

.perspective {
  position: absolute;
  perspective: 1400px;
  perspective-origin: 10% 0;
  z-index: 5;
  margin-top: -143px;
}

.perspective .time_reflection {
  position: absolute;
  transform-style: preserve-3d;
  display: flex;
}

.time_reflection span {
  display: inline-block;
  clip-path: polygon(0 50%, 100% 50%, 100% 100%, 0 100%);
}

.time_prev {
  display: flex;
  margin-top: -143px;
  position: absolute;
  clip-path: polygon(0 50%, 100% 50%, 100% 100%, 0 100%);
  z-index: 4;
  filter: brightness(50%);
}

.time_prev span {}

@keyframes stay {
  from {
    transform: rotateX(0deg);
  }
  to {
    transform: rotateX(0deg);
  }
}

@keyframes reflect {
  0% {
    transform: rotateX(130deg);
    opacity: 1;
  }
  45% {
    transform: rotateX(0deg);
  }
  50% {
    transform: rotateX(7deg);
  }
  53% {
    transform: rotateX(0deg);
  }
  56% {
    transform: rotateX(5deg);
  }
  60% {
    transform: rotateX(0deg);
  }
  95% {
    transform: rotateX(0deg);
  }
  100% {
    transform: rotateX(0deg);
  }
}

.hours:nth-child(2n),
.min:nth-child(2n),
.sec:nth-child(2n) {
  margin-right: 25px;
}
<div class="main_Timer">
  <div class="clock">

    <div class="time">

      <span class="hours">0</span><span class="hours">0</span><span class="min">0</span><span class="min">0</span><span class="sec">0</span><span class="sec">0</span>
    </div>

  </div>
  <div class="perspective">
    <div class="time_reflection">

      <span class="hours">0</span><span class="hours">0</span><span class="min">0</span><span class="min">0</span><span class="sec">0</span><span class="sec">0</span>
    </div>
  </div>
  <div class="time_prev">

    <span class="hours">0</span><span class="hours">0</span><span class="min">0</span><span class="min">0</span><span class="sec">0</span><span class="sec">0</span>
  </div>
  <div class="line_hor"></div>
</div>

关于javascript - 如何在 Angular 中实现翻转时钟,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65442279/

相关文章:

javascript - Angular 中不存在 3

javascript - onchange ="javascript:updateModel()" 'javascript' 这个词有什么作用?

jquery - 在容器边界之外启用 bxSlider

html - 根据下面的宽度 <td> 确定 <td> 的宽度?

javascript - 检查单词是否存在两次? (正则表达式)

javascript - 电话间隙 3.0.0 : BarcodeScanner Plugin

html - CSS:框+图像上的文字

html 幻灯片无法正确显示图像

html - :not all of child element use css?

javascript - 为什么我得到 undefined is not a function ?