JS 面向对象 实现烟花特效
程序员文章站
2024-03-18 10:20:58
...
基本效果如图:
这里的烟花特效 是配合鼠标点击去实现的 (你要是想绑定别的事件也可)
- 创建一个烟花,从底部升起运动到目标位置
- 到达目标位置之后,删除它的同时 炸出一堆烟花
HTML布局+CSS样式
<div class="container"></div>
<style>
.container{
width: 80%;
height: 300px;
border: 2px solid red;
background: #000;
margin:20px auto;
cursor: pointer;
position: relative;
left: 0;
top: 0;
overflow: hidden;
}
.fire{
width: 10px;
height:10px;
position: absolute;
bottom: 0;
}
</style>
JavaScript代码
// OOA
// 1.创建一个烟花元素
// 2.元素运动 运动结束之后删除
// 3.烟花爆炸 循环多个烟花 爆炸之后也要删除
// 4.随机位置
// 5.烟花的随机颜色
// OOD
// function Firework(x,y){
// this.init(x,y);
// }
// Firework.prototype = {
// constructor : Firework,
// // 初始化
// init : function(x,y){//xy是目标位置
// // 创建元素
// // 元素运动 把目标点当做参数x、y
// // 调用函数
// },
// // 1.创建元素
// createFireWorkEle : function(){
// },
// // 2.元素运动
// fireWorkUp : function(ele){
// // 两部分运动 left直接到达、top运动达到
// },
// // 3.烟花爆炸
// fireWorkBlast : function(){
// // 3.1创建非常多的元素
// },
// // 4.随机位置
// randomBoundary : function(){
// },
// // 5.随机颜色
// randomColor : function(ele){
// }
// }
<script>
// OOP
function Firework(x,y , selector){
// 选择父级元素
this.main = document.querySelector(selector);
this.init(x,y);
}
Firework.prototype = {
constructor : Firework,
// 初始化
init : function(x,y){
//x、y是点击事件创建的烟花的位置
this.x = x;
this.y = y;
// 创建元素
this.ele = this.createFireWorkEle();
// 爆炸烟花的随机位置 最大值
this.left_max = this.main.offsetWidth - this.ele.offsetWidth;
this.top_max = this.main.offsetHeight - this.ele.offsetHeight;
// 元素添加背景色
this.randomColor(this.ele);
// 烟花主体升起
this.fireWorkUp(this.ele );
// 烟花爆炸
this.fireWorkBlast(this.ele);
},
// 1.创建元素
createFireWorkEle : function(){
// 往containe里面放进一个烟花fire
var ele = document.createElement("div");
ele.className = "fire";
// 在页面显示
this.main.appendChild(ele);
return ele;
},
// 2.元素运动
fireWorkUp : function(ele){
// 两部分的运动 left直接到达、top运动达到
ele.style.left = this.x + "px";
animate(ele, {top : this.y} , function(){
// 烟花运动结束后 要删除它
// console.log(this);//这时候指向windoe,用bind修改指向
ele.remove();
// 然后调用烟花爆炸
this.fireWorkBlast();
}.bind(this));
},
// 3.烟花爆炸
fireWorkBlast : function(){
// 3.1创建非常多的元素
for(var i = 0 ; i < 20 ; i ++){
var ele = this.createFireWorkEle();
this.randomColor(ele);
// 3.1初始样式设置
ele.style.left = this.x + "px";
ele.style.top = this.y + "px";
// 和点击之后创建的烟花 区分开
ele.style.borderRadius = "50%";
// 3.3让元素有运动目标
animate(ele , this.randomBoundary(ele) , function(callback_ele){
// 爆炸之后删除所有元素
// 用bind 给每个匿名函数都绑定一个ele。否则只会删除最后一个ele
callback_ele.remove();
}.bind(this , ele));
}
},
// 4.随机位置
randomBoundary : function(){
// min 是0
// max中offset性能消耗大,所以放在init()里,只获取一次即可
return{
left : parseInt(Math.random()*(this.left_max + 1)),
top : parseInt(Math.random()*(this.top_max + 1))
}
},
// 5.随机颜色
randomColor : function(ele){
// 随机颜色方法很多
var r = parseInt(256 * Math.random());
var g = parseInt(256 * Math.random());
var b = parseInt(256 * Math.random());
var random_color = "rgb("+r + "," + g + "," + b +")";
return ele.style.backgroundColor = random_color;
}
}
document.querySelector(".container").addEventListener("click",function(evt){
var e = evt || event;
new Firework(e.offsetX , e.offsetY , ".container");
})
</script>
script 引入的 "animate.js" 运动封装
// 元素,属性,回调函数(动画执行结束,调用这个函数)
function animate( ele , attr_options , callback ){
// 获取当前属性
for(var attr in attr_options){
// 同时判断是否是opacity属性
attr_options[attr] = {
// 目标点(传入的数据)
target : attr === "opacity" ? attr_options[attr] * 100 : attr_options[attr],
// 元素当前的属性值
iNow : attr === "opacity" ? parseInt( getComputedStyle(ele)[attr] * 100 ) : parseInt( getComputedStyle(ele)[attr])
}
}
// 定时器的开启和关闭
clearInterval( ele.timer );
ele.timer = setInterval( function(){
// 获取运动所必须的值
for(var attr in attr_options){
// 取出每一条数据
var item = attr_options[attr];
// console.log(item , attr);//target和iNow , "属性名"
var target = item.target;
var iNow = item.iNow;
// 计算速度
var speed = (target - iNow) / 10;
// 速度取整
speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
// 运动的终止条件
// (目标 - 当前位置) 的绝对值 <= 速度 , 此时判定已经到达
if( Math.abs( target - iNow) <= Math.abs(speed) ){
// 送他到底目标点
ele.style[attr] = attr === "opacity" ? target / 100 : target + "px";
// if里的终止条件不严谨:
// 因为目标的不一致会让运动次数执行不同,有可能会提前关闭定时器
// 解决办法:完成一条运动后 删除对象里的数据
delete attr_options[attr];
for(var num in attr_options){
// 如果attr_options里面有属性,不终止定时器
return false;
}
// 如果对象里面没有属性了,就可以关闭定时器
clearInterval(ele.timer);
// 可能会不传callback
typeof callback === "function" ? callback() : "";
}else{
// 元素继续运动
// 如果直接设置iNow 每次循环iNow都会被重置,iNow是一个临时变量
// 所以不能去操作iNow,要去操作iNow的数据源
attr_options[attr].iNow += speed;
ele.style[attr] = attr === "opacity" ? attr_options[attr].iNow / 100 : attr_options[attr].iNow + "px";
}
}
} , 30)
}