话不多说,先看视频,满足所需再往下撸代码(以下代码均基于vue3)
rain
如果也有类似的需求,请往下看:
此效果由两部分组成,落雨+涟漪
雨滴的样式其实是宽1像素,高度不同的白色长方块,下落的动画都是相同的,通过改变长方块的高度,透明度以及动画发生的时间呈现出参差不齐的效果,从而达成落雨的效果,详见下方代码
<template>
<div
v-for="(i, k) in rainData"
:key="k"
class="raindrop"
:style="{
left: i.left + '%',
animationDelay: i.time + 's',
height: i.height + 'px',
opacity: i.opacity + '%',
top: '-' + i.rainTop + 'px',
}"
></div>
</template>
<script>
import { defineComponent, ref, onMounted } from 'vue'
export default defineComponent({
setup() {
const rainData = ref([])
onMounted(() => {
let arr = []
for (let i = 0; i < 30; i++) {
let left = Math.floor(Math.random() * (100 - 1))
let time = Math.random()
let rainTop = Math.floor(Math.random() * (150 - 100)) + 100
let height = Math.floor(Math.random() * (100 - 5)) + 5
let opacity = Math.floor(Math.random() * (60 - 40)) + 40
let top = Math.floor(Math.random() * (90 - 47)) + 47
arr.push({ left, time, height, opacity, rainTop, top })
}
rainData.value = arr
})
return { rainData}
},
})
</script>
<style lang="scss" scoped>
.raindrop {
display: inline-block;
position: absolute;
width: 1px;
background: #ffffff;
border-radius: 5000px;
transform: rotateY(45deg);
animation: raindrop 1s infinite;
}
@keyframes raindrop {
0% {
top: 5%;
}
10% {
top: 10%;
}
20% {
top: 20%;
}
30% {
top: 30%;
}
40% {
top: 40%;
}
50% {
top: 50%;
}
60% {
top: 60%;
}
70% {
top: 70%;
}
80% {
top: 75%;
}
90% {
top: 80%;
}
100% {
top: 85%;
}
}
</style>
涟漪的效果是由若干个同心椭圆形放大消失的动画构成,消失的动画就是一边放大这些椭圆一边改变其的透明度,椭圆的样式详见以下代码:
<template>
<div
v-for="(i, k) in ripplePosition"
:key="k"
class="ripple"
:style="{
left: i.left + 'px',
top: i.top + 'px',
}"
>
<div class="ripple-circle ripple-circle-item1"></div>
<div class="ripple-circle ripple-circle-item2"></div>
<div class="ripple-circle ripple-circle-item3"></div>
</div>
</template>
<script>
import { defineComponent, ref} from 'vue'
export default defineComponent({
setup() {
const ripplePosition = ref([
{ top: '380', left: '170' },
{ top: '275', left: '10' },
{ top: '300', left: '325' },
{ top: '450', left: '300' },
{ top: '480', left: '50' },
{ top: '580', left: '200' },
])
return { ripplePosition }
},
})
</script>
<style lang="scss" scoped>
.ripple {
position: relative;
top: 450px;
left: 300px;
}
.ripple-circle {
display: inline-block;
position: absolute;
border: 1px solid #fff;
border-radius: 50%;
transform: rotateX(72deg);
animation: ripple 1.2s infinite;
&-item1 {
width: 30px;
height: 30px;
top: 20px;
left: 20px;
}
&-item2 {
width: 50px;
height: 50px;
top: 10px;
left: 10px;
}
&-item3 {
width: 70px;
height: 70px;
top: 0;
left: 0;
animation: ripple 1.2s 0.8s infinite;
}
}
@keyframes ripple {
0% {
transform: scale(0.6) rotateX(72deg);
opacity: 1;
}
10% {
transform: scale(0.8) rotateX(72deg);
opacity: 0.9;
}
20% {
transform: scale(0.9) rotateX(72deg);
opacity: 0.8;
}
30% {
transform: scale(1.2) rotateX(72deg);
opacity: 0.7;
}
40% {
transform: scale(1.3) rotateX(72deg);
opacity: 0.6;
}
50% {
transform: scale(1.5) rotateX(72deg);
opacity: 0.5;
}
60% {
transform: scale(1.6) rotateX(72deg);
opacity: 0.4;
}
70% {
transform: scale(1.8) rotateX(72deg);
opacity: 0.3;
}
80% {
transform: scale(1.9) rotateX(72deg);
opacity: 0.2;
}
90% {
transform: scale(2) rotateX(72deg);
opacity: 0.1;
}
100% {
transform: scale(2.1) rotateX(72deg);
opacity: 0;
}
}
</style>
最后附上完整代码:
<template>
<div class="rain-box">
<div
v-for="(i, k) in rainData"
:key="k"
class="raindrop"
:style="{
left: i.left + '%',
animationDelay: i.time + 's',
height: i.height + 'px',
opacity: i.opacity + '%',
top: '-' + i.rainTop + 'px',
}"
></div>
<div
v-for="(i, k) in ripplePosition"
:key="k"
class="ripple"
:style="{
left: i.left + 'px',
top: i.top + 'px',
}"
>
<div class="ripple-circle ripple-circle-item1"></div>
<div class="ripple-circle ripple-circle-item2"></div>
<div class="ripple-circle ripple-circle-item3"></div>
</div>
</div>
</template>
<script>
import { defineComponent, ref, onMounted } from 'vue'
export default defineComponent({
setup() {
const rainData = ref([])
const ripplePosition = ref([
{ top: '380', left: '170' },
{ top: '275', left: '10' },
{ top: '300', left: '325' },
{ top: '450', left: '300' },
{ top: '480', left: '50' },
{ top: '580', left: '200' },
])
onMounted(() => {
let arr = []
for (let i = 0; i < 30; i++) {
let left = Math.floor(Math.random() * (100 - 1))
let time = Math.random()
let rainTop = Math.floor(Math.random() * (150 - 100)) + 100
let height = Math.floor(Math.random() * (100 - 5)) + 5
let opacity = Math.floor(Math.random() * (60 - 40)) + 40
let top = Math.floor(Math.random() * (90 - 47)) + 47
arr.push({ left, time, height, opacity, rainTop, top })
}
rainData.value = arr
})
return { rainData, ripplePosition }
},
})
</script>
<style lang="scss" scoped>
@import '~@/styles/vars';
.rain-box {
width: 100%;
min-height: 100vh;
background: #3BD3D3;
overflow: hidden;
}
.raindrop {
display: inline-block;
position: absolute;
width: 1px;
background: #fff;
border-radius: 5000px;
transform: rotateY(45deg);
animation: raindrop 1s infinite;
}
@keyframes raindrop {
0% {
top: 5%;
}
10% {
top: 10%;
}
20% {
top: 20%;
}
30% {
top: 30%;
}
40% {
top: 40%;
}
50% {
top: 50%;
}
60% {
top: 60%;
}
70% {
top: 70%;
}
80% {
top: 75%;
}
90% {
top: 80%;
}
100% {
top: 85%;
}
}
.ripple {
position: relative;
top: 450px;
left: 300px;
}
.ripple-circle {
display: inline-block;
position: absolute;
border: 1px solid #fff;
border-radius: 50%;
transform: rotateX(72deg);
animation: ripple 1.2s infinite;
&-item1 {
width: 30px;
height: 30px;
top: 20px;
left: 20px;
}
&-item2 {
width: 50px;
height: 50px;
top: 10px;
left: 10px;
}
&-item3 {
width: 70px;
height: 70px;
top: 0;
left: 0;
animation: ripple 1.2s 0.8s infinite;
}
}
@keyframes ripple {
0% {
transform: scale(0.6) rotateX(72deg);
opacity: 1;
}
10% {
transform: scale(0.8) rotateX(72deg);
opacity: 0.9;
}
20% {
transform: scale(0.9) rotateX(72deg);
opacity: 0.8;
}
30% {
transform: scale(1.2) rotateX(72deg);
opacity: 0.7;
}
40% {
transform: scale(1.3) rotateX(72deg);
opacity: 0.6;
}
50% {
transform: scale(1.5) rotateX(72deg);
opacity: 0.5;
}
60% {
transform: scale(1.6) rotateX(72deg);
opacity: 0.4;
}
70% {
transform: scale(1.8) rotateX(72deg);
opacity: 0.3;
}
80% {
transform: scale(1.9) rotateX(72deg);
opacity: 0.2;
}
90% {
transform: scale(2) rotateX(72deg);
opacity: 0.1;
}
100% {
transform: scale(2.1) rotateX(72deg);
opacity: 0;
}
}
</style>