<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<style>
#container {
width: 80%;
height: 600px;
border: 1px red solid;
position: relative;
margin: 20px auto;
cursor: pointer;
background: black;
}
.fire {
background: red;
position: absolute;
/* 设置bottom时,top获取为最大值,减去鼠标点击位置 */
bottom: 0px;
width: 6px;
height: 6px;
}
.small-fire {
width: 10px;
height: 10px;
position: absolute;
border-radius: 50%;
}
</style>
<body>
<div id="container">
</div>
<script>
// 1 获取节点,绑定点击事件
let conObj = document.getElementById('container');
conObj.onclick = function (eve) {
// 2 获取点击位置
let pos = {
cx: eve.offsetX,
cy: eve.offsetY
}
new Fire(conObj, pos);
}
/*******实现大烟花*******/
function Fire(conObj, pos) {
// 1 把属性设置为变量
this.pos = pos;
this.conObj = conObj;
// 2 生成div,且追加class
let bigDiv = document.createElement('div');
bigDiv.classList.add('fire');
// console.log(bigDiv);
// 3 设置大烟花的样式
bigDiv.style.left = pos.cx + 'px';
bigDiv.style.background = this.getColor();
// console.log(bigDiv);
// 4 追加到con中
this.conObj.appendChild(bigDiv);
// let that = this;
// 5 调用运动函数,从底部运动到鼠标点击的位置
this.move(bigDiv, { top: this.pos.cy }, () => {
// console.log(that);
// console.log(this);
// 6 清除大烟花,调用小烟花
bigDiv.remove();
this.smallFire()
})
}
/******小烟花*************/
Fire.prototype.smallFire = function () {
// 1 随机生成烟花个数
let num = this.rand(20, 50);
// 2 循环生成div,且添加class
for (let i = 0; i < num; i++) {
let sFire = document.createElement('div');
sFire.className = 'small-fire';
// 3 设置小烟花的位置为鼠标点击的位置
Object.assign(sFire.style, {
top: this.pos.cy + 'px',
left: this.pos.cx + 'px',
background: this.getColor()
})
// 4 追加到页面中
this.conObj.appendChild(sFire)
// 5 随机top,left值,让烟花动起来
let top = this.rand(0, this.conObj.offsetHeight - sFire.offsetHeight);
let left = this.rand(0, this.conObj.offsetWidth - sFire.offsetWidth);
// sFire.style.background
// 6调用运动函数
this.move(sFire, { top, left }, () => {
// console.log(11111);
sFire.remove();
})
}
}
/********随机数方法*******/
Fire.prototype.rand = (min, max) => {
return Math.round(Math.random() * (max - min) + min);
}
/********随机颜色*****/
Fire.prototype.getColor = function () {
// console.log(this);
let c = '#';
for (let i = 0; i < 6; i++) {
c += this.rand(0, 15).toString(16)
}
return c;
}
/*****运动方法****/
// let times = '';
// 函数之间不会互相干扰....
Fire.prototype.move = function (ele, target, cb) {
// clearInterval(times);
var times = setInterval(function () {
// console.log(this);
var onOff = true;
// 遍历运动的方向和目标
for (let attr in target) {
// attr 表示运动的属性
// console.log(attr);
// 获取元素属性的实时值
let tmpVal = parseInt(this.getPos(ele, attr))
// 计算speed
// console.log(tmpVal, attr);
let speed = (target[attr] - tmpVal) / 10;
// 取整
speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
// 停止计时器,当一个属性运动到位置,设置开关状态
if (tmpVal == target[attr]) onOff = true;
// 让元素动起来
ele.style[attr] = tmpVal + speed + 'px';
}
// 判断开关状态,清除定时器
for (var moveAttr in target) {
// 如果不相等,就说明有属性没有运动到位置,定时器不能停止
if (target[moveAttr] !== parseInt(this.getPos(ele, moveAttr))) {
onOff = false;
break;
}
}
if (onOff) {
clearInterval(times);
cb && cb();
}
// console.log(1111);
}.bind(this), 30)
}
// 获取元素的实时位置的函数
Fire.prototype.getPos = function (obj, attr) {
if (obj.currentStyle) { // 获取css的样式
return obj.currentStyle[attr];
} else {
return getComputedStyle(obj)[attr]
}
}
</script>
</body>
</html>