vue3 实现类似气泡的效果

vue yekong

vue 数据可视化大屏 项目中,按照效果图,需要实现一组气泡效果,气泡内有数字以及标题。
这里我们需要实现这里出气泡的大小,位置以及气泡的颜色等信息。将气泡渲染出来后,为了让页面看起来更生动,我们使用gsap来给组件添加一个上下轻微晃动的效果。

效果截图

vue3 实现类似气泡的效果

效果动画

组件代码

<template>
  <div class="container" ref="container">
    <div
        v-for="(item, index) in list"
        :key="index"
        class="circle"
        ref="circle"
        :style="{
          left:item.left,
          top:item.top,
          width:item.size+'px',
          height:item.size+'px',
          color:item.color,
          background: 'linear-gradient(180deg, '+item.color2+' 0%, '+item.color1+' 100%)'
          }"
    >
      <div class="num" :style="{fontSize:item.numSize+'px'}">{{ item.num }}</div>
      <div class="title">{{ item.title }}</div>
    </div>
  </div>
</template>

<script>
import gsap from 'gsap'

export default {
  data() {
    return {
      list: [
        {
          title: '无职称信息',
          num: 5403,
          left: '4%',
          top: '4%',
          size: 94,
          numSize: 24,
          color: 'rgba(4, 206, 247, 1)',
          color1: 'rgba(18, 155, 255, 0.40)',
          color2: 'rgba(18, 155, 255, 0.1)',
        }, {
          title: '高级工程师',
          num: 320,
          left: '24%',
          top: '24%',
          size: 75,
          numSize: 20,
          color: 'rgba(255, 176, 56, 1)',
          color1: 'rgba(255, 176, 56, 0.28)',
          color2: 'rgba(255, 176, 56, 0.1)',
        }, {
          title: '高级工程师',
          num: 320,
          left: '40%',
          top: '10%',
          size: 56,
          numSize: 20,
          color: 'rgba(0, 242, 255, 1)',
          color1: 'rgba(54, 255, 243, 0.10)',
          color2: 'rgba(54, 255, 243, 0.40)',
        }, {
          title: '经济师',
          num: 320,
          left: '61%',
          top: '11%',
          size: 56,
          numSize: 20,
          color: 'rgba(255, 131, 205, 1)',
          color1: 'rgba(255, 131, 205, 0.10)',
          color2: 'rgba(255, 131, 205, 0.40)',
        }, {
          title: '实验师',
          num: 268,
          left: '80%',
          top: '8%',
          size: 56,
          numSize: 20,
          color: 'rgba(189, 255, 0, 1)',
          color1: 'rgba(189, 255, 0, 0.10)',
          color2: 'rgba(189, 255, 0, 0.40)',
        }, {
          title: '助理研究员',
          num: 268,
          left: '7%',
          top: '44%',
          size: 96,
          numSize: 24,
          color: 'rgba(255, 245, 0, 1)',
          color1: 'rgba(250, 255, 0, 0.28)',
          color2: 'rgba(250, 255, 0, 0)',
        }, {
          title: '工程师',
          num: 260,
          left: '32%',
          top: '56%',
          size: 56,
          numSize: 18,
          color: 'rgba(196, 100, 255, 1)',
          color1: 'rgba(171, 70, 251, 0.10)',
          color2: 'rgba(171, 70, 251, 0.40)',
        }, {
          title: '助教',
          num: 260,
          left: '48%',
          top: '44%',
          size: 56,
          numSize: 20,
          color: 'rgba(0, 255, 186, 1)',
          color1: 'rgba(0, 255, 133, 0.10)',
          color2: 'rgba(0, 255, 133, 0.40)',
        }, {
          title: '副教授',
          num: 260,
          left: '64%',
          top: '33%',
          size: 52,
          numSize: 20,
          color: 'rgba(255, 170, 143, 1)',
          color1: 'rgba(255, 138, 131, 0.12)',
          color2: 'rgba(255, 175, 131, 0.40)',
        }, {
          title: '教授',
          num: 260,
          left: '80%',
          top: '47%',
          size: 78,
          numSize: 24,
          color: 'rgba(122, 151, 255, 1)',
          color1: 'rgba(131, 158, 255, 0.10)',
          color2: 'rgba(133, 131, 255, 0.40)',
        },
      ]
    };
  },
  mounted() {
    this.applyShakeAnimation()
  },
  methods: {
    applyShakeAnimation() {
      this.$nextTick(() => {
        const circles = this.$refs.circle;
        circles.forEach((circle) => {
          gsap.fromTo(
              circle,
              1,
              { y: -2 },
              {
                y: 2,
                ease: 'none',
                yoyo: true,
                repeat: -1,
                delay: Math.random()
              }
          );
        });
      });
    }
  },
};
</script>

<style lang="scss" scoped>
.container {
  position: relative;
  width: 100%;
  height: 100%;
  background: url("./assets/huanbg.png") center center no-repeat;
  background-size: 80%;

  .circle {
    position: absolute;
    border-radius: 50%;
    display: flex;
    justify-content: center;
    align-items: center;
    flex-wrap: nowrap;
    flex-direction: column;
    align-content: flex-start;

    .num {
      font-size: 24px;
      font-family: DIN-Bold;
      font-weight: bold;
      line-height: 30px;
    }

    .title {
      font-size: 12px;
      font-family: PingFang SC-Medium, PingFang SC;
      font-weight: 500;
      text-align: center;
    }
  }
}
</style>

喜欢