vue实现气泡运动撞击效果

2022-08-30 09:11:48

本文实例为大家分享了vue实现气泡运动撞击效果的具体代码,供大家参考,具体内容如下封装组件templateulid=mainliv-for=(item,index)incircl...

本文实例为大家分享了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; /http://www.cppcns.com/随机速度
     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.timer编程客栈Arr.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 ball2yphp = 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>

实现效果

vue实现气泡运动撞击效果

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。