vue2彩带飘落组件

336 阅读1分钟

近期的项目中有一个特殊动画,完成任务后的彩带飘落动画,翻阅了一些网上的资料,可以用canvas制作,由于本人对canvas不精通,所以这里还是采用传统方法。(参考了他人博客)

image.png

主要思路:

  • 两个动画:垂直落下 + 边落下边旋转
  • webkitAnimationEnd:监听动画结束时,移除div
  • 通过设置动态style,控制每个彩带飘落时间

使用:

  • 通过在其他组件中,调用全局事件总线触发:
    this.$bus.$on('ribbonFall',() => {
      this.show()
    }),

代码:

<template>
  <div>
    <ul v-if="rainVisible" class="spark-section" id="spark-section">
      <template v-for="(item, index) in rainParams">
        <li
          class="move_1"
          :style="{
            left: item.left,
            animationDuration: item.durTime,
            webkitAnimationDuration: item.durTime,
          }"
          :data-index="index"
          @webkitAnimationEnd="removeDom"
          :key="index"
        >
          <div class="move-item" :class="`spark-${(index + 1) % 5}`"></div>
        </li>
      </template>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      rainVisible: false,
      rainParams: [], // 所有彩带
      timer: null,
      duration: "",
    };
  },
  created() {
    this.settingData = {
      continueTime: 1, // 下彩带时长
      dropWealthNum: 20, // 在对应的时长里面,应该下落多少个彩带
    };
    this.duration = this.settingData.continueTime * 1000;
    this.continueTime = this.settingData.continueTime;
  },
  methods: {
    startRedPacket() {
      const win =document.documentElement.clientWidth || document.body.clientWidth;
      var plusOrMinus = Math.random() < 0.5 ? -1 : 1;
      const left =parseInt(Math.random() * (win - 50) + 0) + Math.random() * 10 * plusOrMinus;
      const rotate = parseInt(Math.random() * (45 - -45) - 45) + "deg"; // 旋转角度
      const durTime = Math.random() * (2.5 - 1.2 + 1) + 1.2 + "s"; // 时间
      
      this.rainParams.push({
        left: left + "px",
        transforms: "rotate(" + rotate + ")",
        durTime: durTime,
        isHide: false,
      });
      setTimeout(() => {
        // 多少时间结束
        clearTimeout(this.timer);
        this.timer = null;
        return false;
      }, this.duration);
      this.timer = setTimeout(() => {
        this.startRedPacket();
      }, Math.round(this.duration / this.settingData.dropWealthNum));
    },

    // 点击弹框
    show() {
      this.rainVisible = true;
      this.startRedPacket();
    },

     removeDom (e) {
      const target = e.currentTarget
      document.querySelector('#spark-section').removeChild(target)
    },

  },
  mounted() {
    this.$bus.$on('ribbonFall',() => {
      this.show()
    }),
    this.$bus.$on('hideRibbon',() => {
      this.rainVisible = false;
    })
  },
};
</script>

<style scoped lang="scss">
.spark-section {
  display: block;
  overflow: hidden;
  position: absolute;
  left: 0px;
  top: 0px;
  height: 100%;
  width: 100%;
  li {
    position: absolute;
    animation: all 3s linear;
    top:-100px;
    z-index: 0;
    &.move_1 {
      animation: aim_move 4s linear 1 forwards;
      position: relative;
    }
    .move-item {
      animation: cicle 2s infinite linear;
      position: absolute;
      left: 0px;
      top: 0px;
    }
    @keyframes cicle {
      0% {
        transform: rotate(0deg);
        left: 10px;
      }
      10% {
        transform: rotate(30deg);
        left: 0px;
      }
      20% {
        transform: rotate(60deg);
        left: -10px;
      }
      30% {
        transform: rotate(90deg);
        left: 0px;
      }
      40% {
        transform: rotate(120deg);
        left: 10px;
      }
      50% {
        transform: rotate(150deg);
        left: 0px;
      }
      60% {
        transform: rotate(180deg);
        left: -10px;
      }
      70% {
        transform: rotate(210deg);
        left: 0px;
      }
      80% {
        transform: rotate(240deg);
        left:10px;
      }
      90% {
        transform: rotate(240deg);
        left:0px;
      }
      100% {
        transform: rotate(270deg);
        left: -10px;
      }
    }
  }
  a {
    display: block;
  }
}
@keyframes aim_move {
  0% {
    transform: translateY(0);
  }
  100% {
    transform: translateY(100vh);
  }
}
.spark-1 {
  width: 12px;
  height: 36px;
  background: #FFE034;
}
.spark-2 {
  width: 12px;
  height: 24px;
  background: #2893FF;
}
.spark-3 {
  width: 8px;
  height: 24px;
  background: #15E3D1;
}
.spark-4 {
  width: 8px;
  height: 24px;
  background: #8A78FD;
}
.spark-0 {
  width: 12px;
  height: 36px;
  background: #FFA933;
}

</style>

可优化地方:

  • 彩带的飘落速度可以优化成变速,这样可以模拟重力感(未实现,请大佬指教)