前端实现落雨+涟漪效果

话不多说,先看视频,满足所需再往下撸代码(以下代码均基于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>

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值