本文实例为大家分享了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>
实现效果
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持阿兔在线工具。