The actual results are as follows:
The specific implementation process is as follows: Because I am doing this for a book application, so many tag names are beginning with book, here to explain. Let’s look at this animation and break it down:
1. Eject the card
2. Card flip animation (difficult point)
3. Fireworks animation (difficult point)
4. Pop up recommended books
The first and fourth pop-up animations are made using the CSS3 keyFrames property.
The eject of an animation is a process of gradually getting bigger and faster to slower. We call it slow to the beginning and fast to the end of the animation.
His implementation uses the ease-In property in the animation and uses the BOTH property for the final state of the animation. The BOTH property is very interesting. It integrates forwards, which means targets being moved retain properties during execution, backwards targets apply their defined values immediately when executing. And retained during animation-delay.
The following CSS code mostly integrates some basic layout Settings and can focus on the &.animation{} section of the code
I animate the pop-up card application for 1 and 4:
.book-card{ position: relative; width: 65%; box-sizing: border-box; border-radius: px2rem(15); background: white; /* Animation-fill-mode: state at the end of the animation (reaching 100%). Values are: Backward (back to the initial state), forward (stop at the final state), None, both. Animations will follow the rules of forwards and backwards, extending animation properties in both directions. */ &.animation { animation: scale .3s ease-in both; @keyframes scale { 0% { transform: scale(0); opacity: 0; } 100% { transform: scale(1); opacity: 1; } } } .book-card-wrapper{ width: 100%; height: 100%; margin-bottom: px2rem(30); @include columnTop; .img-wrapper{ width: 100%; margin-top: px2rem(20); @include center; .img { width: px2rem(90); height: px2rem(130); } } .content-wrapper{ padding: 0 px2rem(20); margin-top: px2rem(20); .content-title{ color: #333; font-weight: bold; font-size: px2rem(18); line-heigth:px2rem(20); max-height: px2rem(40); text-align: center; @include ellipsis2(2) } .content-author{ margin-top: px2rem(10); text-align: center; } .content-category{ color: #999; font-size: px2rem(14); margin-top: px2rem(10); text-align: center; } } .read-btn{ position: absolute; bottom: 0; left: 0; z-index: 1100; width: 100%; border-radius: 0 0 px2rem(15) px2rem(15); padding: px2rem(15) 0; text-align: center; color: white; font-size: px2rem(14); background: $color-blue; }}}Copy the code
I gave 2 card flip animation pop-ups using the animation:
.flap-card-bg { position: relative; width: px2rem(64); height: px2rem(64); border-radius: px2rem(5); background: white; transform: scale(0); opacity: 0; &.animation{ animation: flap-card-move .3s ease-in both; } @keyframes flap-card-move { 0% { transform: scale(0); opacity: 0; } 50% {transform: scale(1.2); opacity: 1; } 75% { transform: scale(.9); opacity: 1; } 100% { transform: scale(1); opacity: 1; } } .flap-card{ width: px2rem(48); height: px2rem(48); @include absCenter; .flap-card-circle{ display: flex; width: 100%; height: 100%; .flap-card-semi-circle{ flex: 0 0 50%; width: 50%; height: 100%; background-repeat: no-repeat; backface-visibility: hidden; } .flap-card-semi-circle-left{ border-radius: px2rem(24) 0 0 px2rem(24); background-position: center right; transform-origin: right; } .flap-card-semi-circle-right{ border-radius: 0 px2rem(24) px2rem(24) 0; background-position: center left; transform-origin: left; } } } .point-wrapper{ z-index: 1500; @include absCenter; .point{ border-radius: 50%; @include absCenter; &.animation { @for $i from 1 to length($moves) { &:nth-child(#{$i}) { @include move($i); } } } } } }Copy the code
I gave 3 smoke bombs to use in the animation:
.point-wrapper{
z-index: 1500;
@include absCenter;
.point{
border-radius: 50%;
@include absCenter;
&.animation {
@for $i from 1 to length($moves) {
&:nth-child(#{$i}) {
@include move($i);
}
}
}
}
}
Copy the code
You can see the flip of those little cards, and the implementation is very complicated, so I take five cards, and I flip them clockwise in a logical way, from light to dark, and then one after the other. So how do you actually do that? See below:
Here is the tag code, bound to pseudo-classes and refs, to manipulate the DOM using the $refs object
<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>
Copy the code
You can see that I’m using a V-for loop to show the images in flapCardList:
export const flapCardList = [
{
r: 255,
g: 102,
_g: 102,
b: 159,
imgLeft: 'url(' + require('@/assets/images/gift-left.png') + ')',
imgRight: 'url(' + require('@/assets/images/gift-right.png') + ')',
backgroundSize: '50% 50%',
zIndex: 100,
rotateDegree: 0
},
{
r: 74,
g: 171,
_g: 171,
b: 255,
imgLeft: 'url(' + require('@/assets/images/compass-left.png') + ')',
imgRight: 'url(' + require('@/assets/images/compass-right.png') + ')',
backgroundSize: '50% 50%',
zIndex: 99,
rotateDegree: 0
},
{
r: 255,
g: 198,
_g: 198,
b: 102,
imgLeft: 'url(' + require('@/assets/images/star-left.png') + ')',
imgRight: 'url(' + require('@/assets/images/star-right.png') + ')',
backgroundSize: '50% 50%',
zIndex: 98,
rotateDegree: 0
},
{
r: 255,
g: 102,
_g: 102,
b: 159,
imgLeft: 'url(' + require('@/assets/images/heart-left.png') + ')',
imgRight: 'url(' + require('@/assets/images/heart-right.png') + ')',
backgroundSize: '50% 50%',
zIndex: 97,
rotateDegree: 0
},
{
r: 59,
g: 201,
_g: 201,
b: 22,
imgLeft: 'url(' + require('@/assets/images/crown-left.png') + ')',
imgRight: 'url(' + require('@/assets/images/crown-right.png') + ')',
backgroundSize: '50% 50%',
zIndex: 96,
rotateDegree: 0
}
]
Copy the code
Each image is stitched together with left and right parts.
Note the use of pseudo classes to bind the image to its zIndex, appearance order
:style="{zIndex: item.zIndex}"
Copy the code
The basic layout code is as follows:
.flap-card{ width: px2rem(48); height: px2rem(48); @include absCenter; .flap-card-circle{ display: flex; width: 100%; height: 100%; .flap-card-semi-circle{ flex: 0 0 50%; width: 50%; height: 100%; background-repeat: no-repeat; backface-visibility: hidden; } .flap-card-semi-circle-left{ border-radius: px2rem(24) 0 0 px2rem(24); background-position: center right; transform-origin: right; } .flap-card-semi-circle-right{ border-radius: 0 px2rem(24) px2rem(24) 0; background-position: center left; transform-origin: left; }}}Copy the code
Some methods operate on images:
// When the image is moving, Preparations at the back of the picture also need to do is move to also want to prepare () {const backFlapCard = this. FlapCardList. [this. Back] backFlapCard rotateDegree = 180 backFlapCard._g = backFlapCard - 5 * 9 this.rotate(this.back, 'back') },Copy the code
Color change
semiCircleStyle(item, dir) {
return {
backgroundColor: `rgb(${item.r},${item.g},${item.b})`,
backgroundSize: item.backgroundSize,
backgroundImage: dir === 'left' ? item.imgLeft : item.imgRight
}
},
Copy the code
The Angle change
rotate(index, type) { 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})` },Copy the code
Changes in the properties of the card as it rotates
flapCardRotate() { 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() } },Copy the code
The logic of how the card works
startFlapCardAnimation() {
this.prepare()
this.task = setInterval(() => {
this.flapCardRotate()
}, this.intervalTime)
},
Copy the code