基本效果如图:
这里的烟花特效 是配合鼠标点击去实现的 (你要是想绑定别的事件也可)
- 创建一个烟花,从底部升起运动到目标位置
- 到达目标位置之后,删除它的同时 炸出一堆烟花
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 }