vue實現氣泡運動撞擊效果

本文實例為大傢分享瞭vue實現氣泡運動撞擊效果的具體代碼,供大傢參考,具體內容如下

封裝組件

<template>
  <ul id="main">
    <li v-for="(item, index) in circleData" :key="index" :class="{'active': item.is_latest_sign_user}">
      <div>
        <span>{{ item.nick_name }}</span>
        <span>簽到</span>
      </div>
    </li>
  </ul>
</template>

<script>

export default {
  data() {
    return {
      circleData: [],
      circleDom: [],
      circleArr: [],
      //初始化運動的最大寬和高,初始定義0
      maxW: 0,
      maxH: 0,
      timer: null,
      timerArr: [],
      count: 0,
    };
  },
  mounted() {
    this.getLatest_sign_users('init')
    this.timer = setInterval((i) => {
      this.count++
      this.getLatest_sign_users()
    }, 5000)
  },
  methods: {
    getLatest_sign_users(type = '') {
      let data = []
      // nick_name: 用戶名
      // is_latest_sign_user: 是否是新簽到用戶
      // gender: 0-女 1-男
      if (this.count === 0) {
        data = [
          {
            id: '1',
            nick_name: '蕭一',
            is_latest_sign_user: true,
            gender: 0
          },
          {
            nick_name: '楊二',
            is_latest_sign_user: true,
            gender: 0
          },
          {
            nick_name: '張三',
            is_latest_sign_user: true,
            gender: 0
          }
        ]
      } else if (this.count === 1) {
        data = [
          {
            nick_name: '蕭一',
            is_latest_sign_user: false,
            gender: 0
          },
          {
            nick_name: '楊二',
            is_latest_sign_user: false,
            gender: 0
          },
          {
            nick_name: '張三',
            is_latest_sign_user: false,
            gender: 0
          },
          {
            nick_name: '李四',
            is_latest_sign_user: true,
            gender: 1
          },
          {
            nick_name: '王五',
            is_latest_sign_user: true,
            gender: 0
          },
          {
            nick_name: '徐六',
            is_latest_sign_user: true,
            gender: 1
          },
          {
            nick_name: '劉七',
            is_latest_sign_user: true,
            gender: 1
          }
        ]
      } else if (this.count === 2) {
        data = [
          {
            nick_name: '蕭一',
            is_latest_sign_user: false,
            gender: 0
          },
          {
            nick_name: '楊二',
            is_latest_sign_user: false,
            gender: 0
          },
          {
            nick_name: '張三',
            is_latest_sign_user: false,
            gender: 0
          },
          {
            nick_name: '李四',
            is_latest_sign_user: false,
            gender: 1
          },
          {
            nick_name: '王五',
            is_latest_sign_user: false,
            gender: 0
          },
          {
            nick_name: '徐六',
            is_latest_sign_user: false,
            gender: 1
          },
          {
            nick_name: '劉七',
            is_latest_sign_user: false,
            gender: 1
          },
          {
            nick_name: '何八',
            is_latest_sign_user: true,
            gender: 0
          },
          {
            nick_name: '柳九',
            is_latest_sign_user: true,
            gender: 0
          },
          {
            nick_name: '甄十',
            is_latest_sign_user: true,
            gender: 1
          },
          {
            nick_name: '十一',
            is_latest_sign_user: true,
            gender: 1
          },
          {
            nick_name: '十二',
            is_latest_sign_user: true,
            gender: 1
          }
        ]
      } else {
        data = [
          {
            nick_name: '蕭一',
            is_latest_sign_user: false,
            gender: 0
          },
          {
            nick_name: '楊二',
            is_latest_sign_user: false,
            gender: 0
          },
          {
            nick_name: '張三',
            is_latest_sign_user: false,
            gender: 0
          },
          {
            nick_name: '李四',
            is_latest_sign_user: false,
            gender: 1
          },
          {
            nick_name: '王五',
            is_latest_sign_user: false,
            gender: 0
          },
          {
            nick_name: '徐六',
            is_latest_sign_user: false,
            gender: 1
          },
          {
            nick_name: '劉七',
            is_latest_sign_user: false,
            gender: 1
          },
          {
            nick_name: '何八',
            is_latest_sign_user: false,
            gender: 0
          },
          {
            nick_name: '柳九',
            is_latest_sign_user: false,
            gender: 0
          },
          {
            nick_name: '甄十',
            is_latest_sign_user: false,
            gender: 1
          },
          {
            nick_name: '十一',
            is_latest_sign_user: false,
            gender: 1
          },
          {
            nick_name: '十二',
            is_latest_sign_user: false,
            gender: 1
          }
        ]
      }
      this.circleData = [...data]
      if (type === 'init') {//初次加載時默認全是新增簽到用戶
        data.forEach(item => item.is_latest_sign_user = true)
      }
      this.$nextTick(() => {
        if (data.length) {
          this.initBubble()
        }
      })
    },
    initBubble() {
      let main = document.getElementById("main");
      let divDom = main.getElementsByClassName("active"); //獲取新增加的dom
      if (!divDom.length) return;

      //清理每個球得定時器
      this.timerArr.forEach(item => {
        clearInterval(item)
      })
      this.timerArr = []

      //給新增加的dom設置寬高
      for (let i = 0; i < divDom.length; i++) {
        let colors = [
          "#EF250A",
          "#830AF6"
        ];
        divDom[i].style.boxShadow = "0 0 20px" + " " + colors[this.circleData[i].gender] + " " + "inset";
        // 10個以上尺寸變小
        divDom[i].style.width = "46px";
        divDom[i].style.height = "46px";
        divDom[i].style.fontSize = "12px";
        divDom[i].style.lineHeight = "16px";
        this.circleDom.push(divDom[i])
      }

      //根據瀏覽器窗口的大小自動調節小球的運動空間
      window.onresize = () => {
        this.maxW = main.clientWidth - divDom[0].clientWidth; //為瞭讓小球不卡在瀏覽器邊緣
        this.maxH = main.clientHeight - divDom[0].clientHeight; // 所以要減去自身的寬高
      };
      onresize();

      //數組對象的初始化
      for (let i = 0; i < this.circleDom.length; i++) {
        let obj = {};
        console.log(this.circleDom[i]);
        if (this.circleDom[i].getAttribute("class") === 'active') {
          obj.x = Math.floor(Math.random() * (this.maxW + 1)); //初始x坐標
          obj.y = Math.floor(Math.random() * (this.maxH + 1)); //初始y坐標
          obj.cx = obj.x + this.circleDom[0].offsetWidth / 2;//圓心x坐標
          obj.cy = obj.y + this.circleDom[0].offsetHeight / 2;//圓心y坐標
          obj.movex = Math.floor(Math.random() * 2); //x軸移動方向
          obj.movey = Math.floor(Math.random() * 2); //y軸移動方向
          obj.speed = 0.2; //隨機速度
          obj.timer = null; //計時器
          obj.index = i; //索引值
          this.circleArr.push(obj)
          //小球位置初始化
          this.circleDom[i].style.left = obj.x + 'px';
          this.circleDom[i].style.top = obj.y + 'px';
        } else {
          //保留之前數據得位置信息,不刷新位置
          obj = this.circleArr[i]
        }
        this.move(obj);
      }
    },

    //移動函數
    move(balls) {
      //每個球單獨有定時器
      balls.timer = setInterval(() => {
        if (balls.movex === 1) {
          //如果往右跑,則一直加速度,碰到邊界,改為反方向運動
          balls.x += balls.speed;
          if (balls.x + balls.speed >= this.maxW) {
            //防止小球出界
            balls.x = this.maxW;
            balls.movex = 0; //小球運動方向發生改變
          }
        } else {
          balls.x -= balls.speed; // 1和0表示正反方向
          if (balls.x - balls.speed <= 0) {
            balls.x = 0;
            balls.movex = 1;
          }
        }
        if (balls.movey === 1) {
          balls.y += balls.speed;
          if (balls.y + balls.speed >= this.maxH) {
            balls.y = this.maxH;
            balls.movey = 0;
          }
        } else {
          balls.y -= balls.speed;
          if (balls.y - balls.speed <= 0) {
            balls.y = 0;
            balls.movey = 1;
          }
        }
        if (this.circleDom[balls.index]) {
          balls.cx = balls.x + this.circleDom[0].offsetWidth / 2;//小球圓心等於:運動中x的值加上自身的半徑
          balls.cy = balls.y + this.circleDom[0].offsetHeight / 2;
          this.circleDom[balls.index].style.left = balls.x + "px"; //小球相對於屏幕的位置
          this.circleDom[balls.index].style.top = balls.y + "px";
          this.crash(balls.index); //每個小球進行碰撞檢測
        }
      }, 25);
      this.timerArr.push(balls.timer)
    },
    //碰撞函數
    crash(a) {
      let container = [...this.circleArr]
      let ball1x = container[a].cx; //在數組中任意球的圓心坐標
      let ball1y = container[a].cy;//思路:先隨便拿一個球,然後遍歷所有球,拿這個球和所有球的圓心距離比較
      for (let i = 0; i < container.length; i++) {
        if (i !== a) { //判斷取出來的球不是本身,才能和其他球進行距離判斷
          let ball2x = container[i].cx; //將其他球的圓心坐標賦值給球2
          let ball2y = container[i].cy;
          //圓心距 求兩個點之間的距離,開平方
          let distence = Math.sqrt((ball1x - ball2x) * (ball1x - ball2x) + (ball1y - ball2y) * (ball1y - ball2y));
          if (distence <= this.circleDom[0].offsetWidth) { //球心距離和求直徑比較
            if (ball1x > ball2x) { //當前位於未知求的右方
              if (ball1y > ball2y) {//預設未知球撞當前球,然後當前球改變運動
                container[a].movex = 1; //1表示為正值,對應的右和下
                container[a].movey = 1;//0表示為負值,對應的左和上
              } else if (ball1y < ball2y) {
                container[a].movex = 1;
                container[a].movey = 0;
              } else {
                container[a].movex = 1;
              }
            } else if (ball1x < ball2x) {
              if (ball1y > ball2y) {
                container[a].movex = 0;
                container[a].movey = 0;
              } else if (ball1y < ball2y) {
                container[a].movex = 0;
                container[a].movey = 1;
              } else {
                container[a].movex = 0;
              }
            } else {
              if (ball1y > ball2y) {
                container[a].movey = 1;
              } else if (ball1y < ball2y) {
                container[a].movey = 0;
              }
            }
          }
        }
      }
    }
  },
  beforeDestroy() {
    //清理每個球得定時器
    this.timerArr.forEach(item => {
      clearInterval(item)
    })
    //清理簽到數據
    clearInterval(this.timer)
  }
};
</script>
<style lang='less' scoped>
#main {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
  padding: 0;

  li {
    position: absolute;
    overflow: hidden;
    -moz-border-radius: 50%;
    -webkit-border-radius: 50%;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;

    &.active {
      animation: scaleBox 1s 1;
    }

    @keyframes scaleBox {
      0% {
        transform: scale(1);
      }
      50% {
        transform: scale(1.2);
      }
      100% {
        transform: scale(1);
      }
    }

    div {
      span {
        display: block;
        width: 100%;
        color: #fff;
        text-align: center;
      }
    }
  }
}
</style>

實現效果

以上就是本文的全部內容,希望對大傢的學習有所幫助,也希望大傢多多支持WalkonNet。

推薦閱讀: