基本效果如圖:
這里的煙花特效 是配合鼠標點擊去實現的 (你要是想綁定別的事件也可)
- 創建一個煙花,從底部升起運動到目標位置
- 到達目標位置之后,刪除它的同時 炸出一堆煙花
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 }