手摸手寫一個時間翻頁計時器animation動畫

項目須要寫了一個翻頁的計時器,項目基於vue,裏面內容涉及組件知識,樣式以下圖:


本組件分紅兩個組件,一個是單獨的一個反轉的數字,另外一個是把這個翻頁組成一個計時器。css

先分析單獨翻轉的數據動畫:(先拋代碼)

countTurn.vue

<template>
  <div id="stage-1" class="stage stage-state-default">
  <div class="stage-content">
    <ul class="stage-1-icon">
      <li :class="'stage-1-icon-1'">
        <div class="stage-1-icon-top" :class="change?'turn-top':''" :style="{backgroundImage:'url('+pic1+')'}">
        </div>
        <div class="stage-1-icon-bottom" :style="{backgroundImage:'url('+pic1+')'}">
        </div>
      </li>
      <li :class="'stage-1-icon-2'">
        <div class="stage-1-icon-top" :style="{backgroundImage:'url('+pic2+')'}">
        </div>
        <div class="stage-1-icon-bottom" :class="change?'turn-bottom':''" :style="{backgroundImage:'url('+pic2+')'}">
        </div>
      </li>
    </ul>
  </div>
</div>
</template>
<script>
import pic1 from '../../assets/count/1.png'//圖片素材
import pic2 from '../../assets/count/2.png'
import pic3 from '../../assets/count/3.png'
import pic4 from '../../assets/count/4.png'
import pic5 from '../../assets/count/5.png'
import pic6 from '../../assets/count/6.png'
import pic7 from '../../assets/count/7.png'
import pic8 from '../../assets/count/8.png'
import pic9 from '../../assets/count/9.png'
import pic0 from '../../assets/count/0.png'
const picList = [pic0, pic1, pic2, pic3, pic4, pic5, pic6, pic7, pic8, pic9]
export default {
  props: ['num'],
  data() {
    return {
      change: false,
      pic1: pic1,
      pic2: pic2,
    }
  },
  watch: {
    num(newVal, oldVal) { // 當數據改變時觸發動畫
      this.pic1 = picList[oldVal]
      this.pic2 = picList[newVal]
      this.change = false
      setTimeout(() => {
        this.change = true
      }, 100)
    },
  },
  mounted() {
    if (this.num) {// 數字初始化爲0
      ;(this.pic1 = picList[this.num]), (this.pic2 = pic1[this.num + 1 == 10 ? 0 : this.num])
    } else {
      ;(this.pic1 = pic0), (this.pic2 = pic1)
    }
  },
}
</script>
<style lang="less" scoped>
ol,
ul {
  list-style: none;
}
 
#stage-1 .stage-content {
  margin: auto 0 auto;
}
 
.stage-1-icon {
  width: 20px; // 圖片寬度
  height: 37px; // 圖片高度
  margin: 0 auto 0;
  position: relative;
  -webkit-perspective: 900px;
}
 
.stage-1-icon-top,
.stage-1-icon-bottom {
  width: 20px; // 圖片寬度
  position: absolute;
  left: 0;
  background-color: #0342aa;// 背景色
  background-repeat: no-repeat;
  -webkit-transform-style: preserve-3d;
}
 
.stage-1-icon-top {
  height: 18px; //上半截的高度
  padding: 0;
  top: 0;
  background-position: center 0;
  -webkit-transform-origin: center bottom;
  -moz-transform-origin: center bottom;
  -ms-transform-origin: center bottom;
  -o-transform-origin: center bottom;
  transform-origin: center bottom;// 作-webkit-、-moz-、-ms-、-o-兼容
}
 
.stage-1-icon-bottom {
  height: 18px; // 下半截的高度
  top: 18px; // 下半截的位移高度
  // padding: 0 10px 10px;
  background-position: center -18px; // 下半截的背景圖位移高度
  // ……,作-webkit-、-moz-、-ms-、-o-兼容
  transform-origin: center top;
}
 
.stage-1-icon-1 .stage-1-icon-top,
.stage-1-icon-1 .stage-1-icon-bottom {
  z-index: 6; // 初始化更小數字的圖片在上面
  background-size: 100% 200%;
}
 
.stage-1-icon-2 .stage-1-icon-top,
.stage-1-icon-2 .stage-1-icon-bottom {
  z-index: 5; // 初始化更大數字的圖片在下面
  background-size: 100% 200%;
}
@-webkit-keyframes flipover-top {
  0% {
    z-index: 8;// 這是數字上半塊的z-index
    background-color: #0342aa;
    -webkit-transform: rotateX(0);
  }
  50% {
    z-index: 8;
    background-color: rgba(0, 0, 0, 0.1);
    -webkit-transform: rotateX(-90deg);
  }
  50.1% {
    z-index: 7;// 注意z-index的改變
    opacity: 1;
  }
  100% {
    z-index: 7;
    background-color: #0342aa;
    opacity: 0;// 結束時直接透明啦
    -webkit-transform: rotateX(-180deg);
  }
}
@-moz-keyframes flipover-top {
  ……
}
@-ms-keyframes flipover-top {
  ……
}
@-o-keyframes flipover-top {
  ……
}
@keyframes flipover-top {
  ……
}
@-webkit-keyframes flipover-bottom {
  0% {
    z-index: 7;
    background-color: #0342aa;
    -webkit-transform: rotateX(180deg);
  }
  50% {
    z-index: 7;
    background-color: rgba(0, 0, 0, 0.1);
    -webkit-transform: rotateX(90deg);
  }
  50.1% {
    z-index: 8;
  }
  100% {
    z-index: 6;// 結束時把它調整爲數字較少圖的那一層,看.stage-1-icon-1 .stage-1-icon-top的z-index
    background-color: #0342aa;
    -webkit-transform: rotateX(0);
  }
}
@-moz-keyframes flipover-bottom {
  ……
}
@-ms-keyframes flipover-bottom {
  ……
}
@-o-keyframes flipover-bottom {
  ……
}
@keyframes flipover-bottom {
  ……
}
#stage-1.stage-state-default {
  z-index: 1;
}
.turn-top { // 上半塊動畫
  // ……,作-webkit-、-moz-、-ms-、-o-兼容
  animation: flipover-top 0.15s linear 0s 1 normal forwards;
}
.turn-bottom { // 下半塊動畫
  // ……,作-webkit-、-moz-、-ms-、-o-兼容
  animation: flipover-bottom 0.15s linear 0s 1 normal forwards;
}
</style>
複製代碼

(兼容性的代碼太長註釋掉了 自行加上哈)html

上面注意的知識點有如下幾點:vue

1.圖片根據background-image引入

一張圖片,經過background-image引入,並且分紅上下兩塊。web

<div class="stage-1-icon-top" :class="change?'turn-top':''" :style="{backgroundImage:'url('+pic1+')'}"></div>
<div class="stage-1-icon-bottom" :style="{backgroundImage:'url('+pic1+')'}"></div>
複製代碼

2.用change屬性從新觸發動畫 html:bash

<div class="stage-1-icon-top" :class="change?'turn-top':''" :style="{backgroundImage:'url('+pic1+')'}"></div>
 …… 

<div class="stage-1-icon-bottom" :class="change?'turn-bottom':''" :style="{backgroundImage:'url('+pic2+')'}">
複製代碼

 js:
less

num(newVal, oldVal) {
      this.pic1 = picList[oldVal]
      this.pic2 = picList[newVal]
      this.change = false // 改爲false
      setTimeout(() => {  
        this.change = true // 過零點一毫秒再改成true
      }, 100)
    },
複製代碼

css:函數

.turn-top { // 上半塊動畫
  // ……,作-webkit-、-moz-、-ms-、-o-兼容
  animation: flipover-top 0.15s linear 0s 1 normal forwards;
}
.turn-bottom { // 下半塊動畫
  // ……,作-webkit-、-moz-、-ms-、-o-兼容
  animation: flipover-bottom 0.15s linear 0s 1 normal forwards;
}
複製代碼

3.注意每一塊的z-index關係

每一個寫有z-index的地方都要留意,由於是關鍵鴨!性能


分析父級組件如何製做計時器(先拋代碼)

timer.vueflex

<template>
  <div class="timer">
    <countTurn :num="hh"></countTurn>
    <countTurn :num="h"></countTurn>
    <img src="../../assets/count/_.png" class="img" alt=":">
    <countTurn :num="mm"></countTurn>
    <countTurn :num="m"></countTurn>
    <img src="../../assets/count/_.png" class="img" alt=":">
    <countTurn :num="ss"></countTurn>
    <countTurn :num="s"></countTurn>
  </div>
</template>
<script>
import countTurn from '../countTurn' //子組件引入
let timer = null
export default {
  components: {countTurn},
  data() {
    return {
      hh: 0,
      h: 0,
      mm: 0,
      m: 0,
      ss: 0,
      s: 0,
    }
  },
  mounted() {
    this.startTimer(new Date())
    setInterval(() => {
      this.startTimer(new Date())
    }, 1000 * 60 * 60) // 一小時跟進一下實際時間防止系統卡頓產生計時偏差
  },
  methods: {
    startTimer(date) {
      if (timer) {
        clearInterval(timer)
      }
      let dt = new Date(date)
      // 初始化6個值
      this.hh = dt.getHours() >= 10 ? Math.floor(dt.getHours() / 10) : 0
      this.h = dt.getHours() % 10
      this.mm = dt.getMinutes() >= 10 ? Math.floor(dt.getMinutes() / 10) : 0
      this.m = dt.getMinutes() % 10
      this.ss = dt.getSeconds() >= 10 ? Math.floor(dt.getSeconds() / 10) : 0
      this.s = dt.getSeconds() % 10
 
      // 開始計時
      timer = setInterval(() => {
        this.s++
        if (this.s == 10) {
          this.s = 0
          this.ss++
          if (this.ss == 6) {
            this.ss = 0
            this.m++
            if (this.m == 10) {
              this.m = 0
              this.mm++
              if (this.mm == 6) {
                this.mm = 0
                this.h++
                if (this.hh * 10 + this.h == 24) {
                  this.hh = 0
                  this.h = 0
                } else if (this.h == 10) {
                  this.h = 0
                  this.hh++
                }
              }
            }
          }
        }
      }, 1000)
    },
  },
}
</script>
<style lang="less" scoped>
.timer {
  display: flex;
  align-items: center;
  justify-content: center;
}
.img{
  width: 10px;
}
</style>
複製代碼

這一塊代碼主要重點在於計時的函數startTimer() 動畫

 1.使用setInterval()1秒循環一次 

2.一小時跟進一下實際時間防止系統卡頓產生計時偏差再調用一次startTime(),因此在函數開始時先清一下以前的計時器clearInterval(timer),而後再從新獲取一次時間。 

3.爲何這裏不直接每一秒都獲取一下時間呢?

每秒都拿一次會影響性能 大體分享到這裏,圖片使用本身的圖片替代就能夠啦~ 

ps: 第一次寫掘金的文章,有什麼不足請多多指點。

相關文章
相關標籤/搜索