本组件分成两个组件,一个是单独的一个反转的数字,另一个是把这个翻页组成一个计时器。
先分析单独翻转的数据动画:(先抛代码)
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>
(兼容性的代码太长注释掉了 自行加上哈)
上面注意的知识点有以下几点:
1.图片根据background-image引入
一张图片,通过background-image引入,而且分成上下两块。
<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:
<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:
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.vue
<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: 第一次写掘金的文章,有什么不足请多多指点。