基本效果如图:
这里的烟花特效 是配合鼠标点击去实现的 (你要是想绑定别的事件也可)
- 创建一个烟花,从底部升起运动到目标位置
- 到达目标位置之后,删除它的同时 炸出一堆烟花
HTML布局+CSS样式
<div class="container"></div>
1 <style> 2 .container{ 3 width: 80%; 4 height: 300px; 5 border: 2px solid red; 6 background: #000; 7 margin:20px auto; 8 cursor: pointer; 9 position: relative; 10 left: 0; 11 top: 0; 12 overflow: hidden; 13 } 14 .fire{ 15 width: 10px; 16 height:10px; 17 position: absolute; 18 bottom: 0; 19 } 20 </style>
JavaScript 代码
1 <script> 2 // OOA 3 // 1.创建一个烟花元素 4 // 2.元素运动 运动结束之后删除 5 // 3.烟花爆炸 循环多个烟花 爆炸之后也要删除 6 // 4.随机位置 7 // 5.烟花的随机颜色 8 // OOD 9 // function Firework(x,y){ 10 // this.init(x,y); 11 // } 12 13 // Firework.prototype = { 14 // constructor : Firework, 15 // // 初始化 16 // init : function(x,y){//xy是目标位置 17 // // 创建元素 18 // // 元素运动 把目标点当做参数x、y 19 // // 调用函数 20 21 // }, 22 // // 1.创建元素 23 // createFireWorkEle : function(){ 24 25 // }, 26 // // 2.元素运动 27 // fireWorkUp : function(ele){ 28 // // 2部分运动 left直接到达、top运动达到 29 // }, 30 // // 3.烟花爆炸 31 // fireWorkBlast : function(){ 32 // // 3.1创建非常多的元素 33 // }, 34 // // 4.随机位置 35 // randomBoundary : function(){ 36 37 // }, 38 // // 5.随机颜色 39 // randomColor : function(ele){ 40 41 // } 42 // } 43 44 // OOP 45 function Firework(x,y , selector){ 46 // 选择父级元素 47 this.main = document.querySelector(selector); 48 49 this.init(x,y); 50 } 51 52 Firework.prototype = { 53 constructor : Firework, 54 // 初始化 55 init : function(x,y){ 56 //x、y是点击事件创建的烟花的位置 57 this.x = x; 58 this.y = y; 59 60 // 创建元素 61 this.ele = this.createFireWorkEle(); 62 // 爆炸烟花的随机位置 最大值 63 this.left_max = this.main.offsetWidth - this.ele.offsetWidth; 64 this.top_max = this.main.offsetHeight - this.ele.offsetHeight; 65 66 // 元素添加背景色 67 this.randomColor(this.ele); 68 // 烟花主体升起 69 this.fireWorkUp(this.ele ); 70 // 烟花爆炸 71 this.fireWorkBlast(this.ele); 72 }, 73 // 1.创建元素 74 createFireWorkEle : function(){ 75 // 往containe里面放进一个烟花fire 76 var ele = document.createElement("div"); 77 ele.className = "fire"; 78 // 在页面显示 79 this.main.appendChild(ele); 80 return ele; 81 }, 82 // 2.元素运动 83 fireWorkUp : function(ele){ 84 // 两部分的运动 left直接到达、top运动达到 85 ele.style.left = this.x + "px"; 86 animate(ele, {top : this.y} , function(){ 87 // 烟花运动结束后 要删除它 88 // console.log(this);//这时候指向windoe,用bind修改指向 89 ele.remove(); 90 // 然后调用烟花爆炸 91 this.fireWorkBlast(); 92 }.bind(this)); 93 }, 94 // 3.烟花爆炸 95 fireWorkBlast : function(){ 96 // 3.1创建非常多的元素 97 for(var i = 0 ; i < 20 ; i ++){ 98 var ele = this.createFireWorkEle(); 99 this.randomColor(ele); 100 // 3.1初始样式设置 101 ele.style.left = this.x + "px"; 102 ele.style.top = this.y + "px"; 103 // 和点击之后创建的烟花 区分开 104 ele.style.borderRadius = "50%"; 105 // 3.3让元素有运动目标 106 animate(ele , this.randomBoundary(ele) , function(callback_ele){ 107 // 爆炸之后删除所有元素 108 // 用bind 给每个匿名函数都绑定一个ele。否则只会删除最后一个ele 109 callback_ele.remove(); 110 }.bind(this , ele)); 111 } 112 }, 113 // 4.随机位置 114 randomBoundary : function(){ 115 // min 是0 116 // max中offset性能消耗大,所以放在init()里,只获取一次即可 117 return{ 118 left : parseInt(Math.random()*(this.left_max + 1)), 119 top : parseInt(Math.random()*(this.top_max + 1)) 120 } 121 }, 122 // 5.随机颜色 123 randomColor : function(ele){ 124 // 随机颜色方法很多 125 var r = parseInt(256 * Math.random()); 126 var g = parseInt(256 * Math.random()); 127 var b = parseInt(256 * Math.random()); 128 var random_color = "rgb("+r + "," + g + "," + b +")"; 129 return ele.style.backgroundColor = random_color; 130 131 } 132 } 133 134 document.querySelector(".container").addEventListener("click",function(evt){ 135 var e = evt || event; 136 new Firework(e.offsetX , e.offsetY , ".container"); 137 }) 138 </script>
<script>引入的 "animate.js" 运动封装
1 // 元素,属性,回调函数(动画执行结束,调用这个函数) 2 function animate( ele , attr_options , callback ){ 3 // 获取当前属性 4 for(var attr in attr_options){ 5 // 同时判断是否是opacity属性 6 attr_options[attr] = { 7 // 目标点(传入的数据) 8 target : attr === "opacity" ? attr_options[attr] * 100 : attr_options[attr], 9 // 元素当前的属性值 10 iNow : attr === "opacity" ? parseInt( getComputedStyle(ele)[attr] * 100 ) : parseInt( getComputedStyle(ele)[attr]) 11 } 12 } 13 // 定时器的开启和关闭 14 clearInterval( ele.timer ); 15 ele.timer = setInterval( function(){ 16 // 获取运动所必须的值 17 for(var attr in attr_options){ 18 // 取出每一条数据 19 var item = attr_options[attr]; 20 // console.log(item , attr);//target和iNow , "属性名" 21 var target = item.target; 22 var iNow = item.iNow; 23 // 计算速度 24 var speed = (target - iNow) / 10; 25 // 速度取整 26 speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed); 27 // 运动的终止条件 28 // (目标 - 当前位置) 的绝对值 <= 速度 , 此时判定已经到达 29 if( Math.abs( target - iNow) <= Math.abs(speed) ){ 30 // 送他到底目标点 31 ele.style[attr] = attr === "opacity" ? target / 100 : target + "px"; 32 // if里的终止条件不严谨: 33 // 因为目标的不一致会让运动次数执行不同,有可能会提前关闭定时器 34 // 解决办法:完成一条运动后 删除对象里的数据 35 delete attr_options[attr]; 36 37 for(var num in attr_options){ 38 // 如果attr_options里面有属性,不终止定时器 39 return false; 40 } 41 // 如果对象里面没有属性了,就可以关闭定时器 42 clearInterval(ele.timer); 43 // 可能会不传callback 44 typeof callback === "function" ? callback() : ""; 45 }else{ 46 // 元素继续运动 47 // 如果直接设置iNow 每次循环iNow都会被重置,iNow是一个临时变量 48 // 所以不能去操作iNow,要去操作iNow的数据源 49 attr_options[attr].iNow += speed; 50 ele.style[attr] = attr === "opacity" ? attr_options[attr].iNow / 100 : attr_options[attr].iNow + "px"; 51 } 52 } 53 } , 30) 54 }