在VUE实战项目的中有一个加载推荐书籍的过渡动画,在项目中是使用JS实现。
当时看视频大概一个小时作用,拆分动画逻辑,写代码更是耗时。后来自己想着能不能用CSS动画直接写出来,折腾了半天,终于算是实现了。
可以查看加载动画地址
/*首先是DOM结构,不能像js一样分左右两边,正面翻为反面还要改变z-index,按照同样的布局也尝试过,没有用CSS动画写出来,逻辑太复杂。
这是一个类似翻书一样的动画效果,想着结构分为一页一页,一页旋转180°,完成时再改变“这一页”的z-index。每个page类的before伪类为正面,after伪类为反面;分解5页的在每一秒的动画,写出各自的animation。
*/
<div class="card">
<div class="page"></div>
<div class="page"></div>
<div class="page"></div>
<div class="page"></div>
<div class="page"></div>
</div>
.card{
width: 50px;
height: 50px;
opacity: 0;
position: relative;
animation: .5s all;
}
.card .page{
width: 50%;
height: 100%;
position: absolute;
left: 50%;
top: 0;
transform-style: preserve-3d;
transform-origin: left;
}
.card .page::before, .card .page::after{
content: '';
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
border-radius: 0px 50px 50px 0px;
}
.card .page::after{
border-radius: 50px 0px 0px 50px;
}
.card .page:nth-child(1){
animation: animation1 2s linear infinite;
}
.card .page:nth-child(2){
animation: animation2 2s linear infinite;
}
.card .page:nth-child(3){
animation: animation3 2s linear infinite;
}
.card .page:nth-child(4){
animation: animation4 2s linear infinite;
}
.card .page:nth-child(5){
animation: animation5 2s linear infinite;
}
.card .page:nth-child(1)::before{
background: aqua url("./images/star-right.png") center left/50% 50% no-repeat;
}
.card .page:nth-child(1)::after{
background: hotpink url("./images/compass-left.png") center right/50% 50% no-repeat;
transform: rotateY(180deg);
}
.card .page:nth-child(2)::before{
background: hotpink url("./images/compass-right.png") center left/50% 50% no-repeat;
}
.card .page:nth-child(2)::after{
background: coral url("./images/crown-left.png") center right/50% 50% no-repeat;
transform: rotateY(180deg);
}
.card .page:nth-child(3)::before{
background: coral url("./images/crown-right.png") center left/50% 50% no-repeat;
}
.card .page:nth-child(3)::after{
background: cyan url("./images/gift-left.png") center right/50% 50% no-repeat;
transform: rotateY(180deg);
}
.card .page:nth-child(4)::before{
background: cyan url("./images/gift-right.png") center left/50% 50% no-repeat;
}
.card .page:nth-child(4)::after{
background: yellowgreen url("./images/heart-left.png") center right/50% 50% no-repeat;
transform: rotateY(180deg);
}
.card .page:nth-child(5)::before{
background: yellowgreen url("./images/heart-right.png") center left/50% 50% no-repeat;
}
.card .page:nth-child(5)::after{
background: aqua url("./images/star-left.png") center right/50% 50% no-repeat;
transform: rotateY(180deg);
}
@keyframes animation1 {
0%{
z-index: 1;
transform: rotateY(180deg);
}
20%{
z-index: 1;
transform: rotateY(180deg);
}
40%{
z-index: 3;
transform: rotateY(360deg);
}
60%{
z-index: 4;
transform: rotateY(360deg);
}
60.0001%{
z-index: 4;
transform: rotateY(0deg);
}
80%{
z-index: 5;
transform: rotateY(0deg);
}
100%{
z-index: 4;
transform: rotateY(180deg);
}
}
@keyframes animation2 {
0%{
z-index: 5;
transform: rotateY(0deg);
}
20%{
z-index: 4;
transform: rotateY(180deg);
}
40%{
z-index: 1;
transform: rotateY(180deg);
}
60%{
z-index: 3;
transform: rotateY(360deg);
}
80%{
z-index: 4;
transform: rotateY(360deg);
}
100%{
z-index: 5;
transform: rotateY(360deg);
}
}
@keyframes animation3 {
0%{
z-index: 4;
transform: rotateY(0deg);
}
20%{
z-index: 5;
transform: rotateY(0deg);
}
40%{
z-index: 4;
transform: rotateY(180deg);
}
60%{
z-index: 1;
transform: rotateY(180deg);
}
80%{
z-index: 3;
transform: rotateY(360deg);
}
100%{
z-index: 4;
transform: rotateY(360deg);
}
}
@keyframes animation4 {
0%{
z-index: 3;
transform: rotateY(0deg);
}
20%{
z-index: 4;
transform: rotateY(0deg);
}
40%{
z-index: 5;
transform: rotateY(0deg);
}
60%{
z-index: 4;
transform: rotateY(180deg);
}
80%{
z-index: 1;
transform: rotateY(180deg);
}
100%{
z-index: 3;
transform: rotateY(360deg);
}
}
@keyframes animation5 {
0%{
z-index: 2;
transform: rotateY(0deg);
}
20%{
z-index: 3;
transform: rotateY(0deg);
}
40%{
z-index: 4;
transform: rotateY(0deg);
}
60%{
z-index: 5;
transform: rotateY(0deg);
}
80%{
z-index: 4;
transform: rotateY(180deg);
}
100%{
z-index: 1;
transform: rotateY(180deg);
}
}
再贴出JS实现:
<div class="flap-card" v-for="(item, index) in flapCardList" :key="index" :style="{zIndex: item.zIndex}">
<div class="flap-card-circle">
<div class="flap-card-semi-circle flap-card-semi-circle-left" :style="semiCircleStyle(item, 'left')"
ref="left"></div>
<div class="flap-card-semi-circle flap-card-semi-circle-right" :style="semiCircleStyle(item, 'right')"
ref="right"></div>
</div>
</div>
data() {
return {
front: 0,
back: 1,
}
},
methods: {
// flapCardList是存储着图片信息的对象数组,通过v-for循环和semiCircleStyle方法设置5组图片的背景。
semiCircleStyle(item, dir) {
return {
backgroundColor: `rgb(${item.r}, ${item.g}, ${item.b})`,
backgroundSize: item.backgroundSize,
backgroundImage: dir === 'left' ? item.imgLeft : item.imgRight
}
},
rotate(index, type) {
//卡牌翻转,"front"选择右边卡片,否则选择左边卡片;然后改变dom元素的样式
const item = this.flapCardList[index]
let dom
if (type === 'front') {
dom = this.$refs.right[index]
} else {
dom = this.$refs.left[index]
}
dom.style.transform = `rotateY(${item.rotateDegree}deg)`
dom.style.backgroundColor = `rgb(${item.r}, ${item._g}, ${item.b})`
},
flapCardRotate() {
//首先是翻转函数,每次翻转分正反两面。当动画至90°时,改变背面的z-index值,每一帧动画完毕执行rotate函数以改变样式。
const frontFlapCard = this.flapCardList[this.front]
const backFlapCard = this.flapCardList[this.back]
frontFlapCard.rotateDegree += 10
frontFlapCard._g -= 5
backFlapCard.rotateDegree -= 10
if (backFlapCard.rotateDegree < 90) {
backFlapCard._g += 5
}
if (frontFlapCard.rotateDegree === 90 && backFlapCard.rotateDegree === 90) {
backFlapCard.zIndex += 2
}
this.rotate(this.front, 'front')
this.rotate(this.back, 'back')
if (frontFlapCard.rotateDegree === 180 && backFlapCard.rotateDegree === 0) {
this.next()
}
},
prepare() {
const backFlapCard = this.flapCardList[this.back]
backFlapCard.rotateDegree = 180
backFlapCard._g = backFlapCard.g - 5 * 9
this.rotate(this.back, 'back')
},
next() {
const frontFlapCard = this.flapCardList[this.front]
const backFlapCard = this.flapCardList[this.back]
frontFlapCard.rotateDegree = 0
backFlapCard.rotateDegree = 0
frontFlapCard._g = frontFlapCard.g
backFlapCard._g = backFlapCard.g
this.rotate(this.front, 'front')
this.rotate(this.back, 'back')
this.front++
this.back++
const len = this.flapCardList.length
if (this.front >= len) {
this.front = 0
}
if (this.back >= len) {
this.back = 0
}
// 动态设置zIndex
// 100 -> 96
// 99 -> 100
// 98 -> 99
// 97 -> 98
// 96 -> 97
// (0 - 1 + 5) % 5 = 4
// (1 - 1 + 5) % 5 = 0
this.flapCardList.forEach((item, index) => {
item.zIndex = 100 - ((index - this.front + len) % len)
})
this.prepare()
},
startFlapCardAnimation() {
this.prepare()
this.task = setInterval(() => {
this.flapCardRotate()
}, this.intervalTime)
},
stopAnimation() {
//动画停止时,清除所有setTimeout;否则再次进入动画出现错误。
if (this.task) {
clearInterval(this.task)
}
if (this.timeout) {
clearTimeout(this.timeout)
}
if (this.timeout2) {
clearTimeout(this.timeout2)
}
this.reset()
},
runAnimation() {
//点击推荐,则动画开始(vuex中定义了flapCardVisible,watch监听其变化,为TRUE则动画开始)
this.runFlapCardAnimation = true
this.timeout = setTimeout(() => {
this.startFlapCardAnimation()
this.startPointAnimation()
}, 300)
this.timeout2 = setTimeout(() => {
this.stopAnimation()
//2500ms过渡动画结束,推荐图书显示
this.runBookCardAnimation = true
}, 2500)
},
watch: {
flapCardVisible(v) {
if (v) {
this.runAnimation()
}
}
},
}
写在最后:初次写CSS动画的总结,而且感觉自己的实现并不是很好,应该有更简单些的实现方法。从DOM结构设计,到动画过程分析还欠缺很多。并且一个动画如此费时,在实际项目中应该得不偿失。还是需要大量的练习,经常练手才可熟能生巧。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。
更新日志
- 小骆驼-《草原狼2(蓝光CD)》[原抓WAV+CUE]
- 群星《欢迎来到我身边 电影原声专辑》[320K/MP3][105.02MB]
- 群星《欢迎来到我身边 电影原声专辑》[FLAC/分轨][480.9MB]
- 雷婷《梦里蓝天HQⅡ》 2023头版限量编号低速原抓[WAV+CUE][463M]
- 群星《2024好听新歌42》AI调整音效【WAV分轨】
- 王思雨-《思念陪着鸿雁飞》WAV
- 王思雨《喜马拉雅HQ》头版限量编号[WAV+CUE]
- 李健《无时无刻》[WAV+CUE][590M]
- 陈奕迅《酝酿》[WAV分轨][502M]
- 卓依婷《化蝶》2CD[WAV+CUE][1.1G]
- 群星《吉他王(黑胶CD)》[WAV+CUE]
- 齐秦《穿乐(穿越)》[WAV+CUE]
- 发烧珍品《数位CD音响测试-动向效果(九)》【WAV+CUE】
- 邝美云《邝美云精装歌集》[DSF][1.6G]
- 吕方《爱一回伤一回》[WAV+CUE][454M]
