由于是面向对象,所以步骤非常重要
**
一.OOA:
**
1. 创建元素;
2. 元素运动;
3. 烟花爆炸;
4. 随机位置;
5. 随机颜色;
二.OOD:
function FireWork( x , y ) {
this.init( x , y );
}
FireWork.prototype = {
constructor : FireWork ,
init : function( x , y ){
},
// 1. 创建元素;
createFireWorkEle : function (){
},
// 2. 元素运动;
fireWorkUp : function(){
},
// 3. 烟花爆炸;
fireWorkBlast : function(){
},
// 4. 随机位置;
randomBoundary : function(){
}
// 5. 随机颜色;
randomColor : function(){
}
}
**
三.OOP
**
首先是布局:
<div class="box"></div>
然后是CSS样式:
<style>
.box{
width: 80%;
height: 600px;
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>
首先要初始化函数:
init : function( x , y ){
//因为元素要运动,所以要初始化x,y坐标
//把初始化出来的x,y坐标指向this
//这里的this指向FireWork实例对象
this.x = x;
this.y = y;
console.log(this,this.x,this.y,x,y);
//因为要有火花,所以要创建元素
//又因为有了创建函数,所以调用函数FireWorkCJ()
this.ele = this.FireWorkCJ();
console.log(this.ele);
// 为了节省randomBoundary消耗的无用性能,统一获取一次left和top的最大值;
// 注意程序的执行顺序, 元素的offset属性获取,必须要放在元素插入到页面之后才行;
this.left_max = this.main.offsetWidth - this.ele.offsetWidth;
this.top_max = this.main.offsetHeight - this.ele.offsetHeight;
//给元素添加背景颜色
this.FireWorkYS( this.ele );
// 烟花主体升起;
this.FireWorkYD( this.ele );
},
创建元素
//1.创建元素
// 什么时候要使用var 什么时候要使用 this.xxx ;
// 如果这个数据在其他的方法里还要用,那么就放在this之中;
// 如果感觉这个变量在当前函数使用结束就不用了,那么就用var;
FireWorkCJ : function(){
//首先要创建一个火花的盒子
var ele = document.createElement("div");
//让他拥有className,成为拥有该样式的盒子
ele.className = "fire";
//将这个火花盒子放到父级
//由于传入了父级参数 selector ,将创建出来的 ele 放到父级
this.main.appendchild( ele );
//返回ele
return ele;
}
,
其次是元素运动
//2.元素运动
FireWorkYD : function( ele ){
//创建元素的左右位置
//left : 直接到达
//top : 运动到达目的地
//创建的元素 ele 的left为 this.x 的位置像素
ele.style.left = this.x + "px";
//调用运动函数
animate( ele ,{
top : this.y
},function(){
// 烟花运动结束要删除掉这个元素;
ele.remove();
// 直接调用烟花爆炸功能;
this.FireWorkBZ();
}.bind(this))
},
强大的爆炸功能
//3.烟花爆炸
FireWorkBZ : function(){
//烟花爆炸,随机生成多个(20)个火花
for( var i = 0 ; i < 20 ; i++){
//创建火花
var ele = this.FireWorkCJ();
this.FireWorkYS( ele );
//初始化火花的样式
ele.style.left = this.x + "px";
ele.style.top = this.y + "px";
ele.style.borderRadius = "50%";
//让元素有运动目标;
animate( ele , this.BZ_type = "circular" ? this.BZ_YUAN( i , 20 ) : this.FireWorkWZ() , function( callback_ele ){
// 什么时候会执行这个回调函数; 一定的时间之后; for循环早就执行完了;
// 在这个作用域之中ele只有一个,当你执行回调函数的时候,ele已经被赋值20次了,ele里面的数据之后最后一个。
// bind 的高级用法;
callback_ele.remove();
}.bind(this , ele))
// 因为执行了20次,会创造20个不同的函数;
// 现在给每个匿名函数都去绑定一个ele元素;
// function( ele ){ ele => ele1 }.bind(this,ele1)
// function( ele ){ ele => ele2 }.bind(this,ele2)
// function( ele ){ ele => ele3 }.bind(this,ele3)
// ...
}
},
爆炸后元素的随机位置
//4.随机位置6
FireWorkWZ : function(){
return {
left : parseInt( Math.random() * ( this.left_max + 1) ),
top : parseInt( Math.random() * ( this.top_max + 1) )
}
},
生成的随机颜色的烟花
//5.随机颜色
//给已经创建出来的ele火花盒子添加随机颜色样式
FireWorkYS : function( ele ){
return ele.style.backgroundColor = "#" + parseInt( parseInt( "ffffff" , 16) * Math.random() ).toString(16).padStart( 6 , 0 );
},
爆炸后呈圆形绽放
//6.扩展:爆炸后呈圆形绽放
//now_index : 代表这是创建的第几个圆
//total : 代表 一共要创建多少个
BZ_YUAN : function( now_index , total ){
var r = 100;
// 计算角度;
//reg : 代表第i个对应的角度
var reg = (360 / total ) * now_index;
// JS里面没有角度只有弧度; 换算弧度;
//deg : 转化成弧度
var deg = Math.PI / 180 * reg;
return {
left : parseInt(r * Math.cos( deg )) + this.x,
top : parseInt(r * Math.sin( deg )) + this.y,
}
}
调用函数
document.querySelector(".box").addEventListener("click",function( evt ){
var e = evt || event;
new FireWork(e.offsetX , e.offsetY , ".box" , "circular")
})
内置js函数
<script src="animate.js"></script>
代码展示
//创建一个可以传入更多数据的函数方法-------回调函数
//作用 :任意元素任意属性运动
//参数解析:
// ele : 元素
// attr_options : 调用的对象结构
// callback : 函数方法
function animate( ele , attr_options , callback){
//获取元素当前的属性
//遍历attr_option结构数组
for( var attr in attr_options ){
// 我们需要记录的数据有 : 属性名 : 目标点, 当前元素的属性;
// { "width" : {
// target : 200 ,
// iNow : 元素的属性值;
// }
// }
// attr : width : height |.......;
//属性名:attr_options[ attr ]
//传入的属性值:attr
//目标 :target
//当前元素的属性:iNow
attr_options[ attr ] = {
// 目标点 : 传入的数据;
//目标点取值
//当 目标点target 取出的 attr 的值 为opacity 时, target = attr_options[ attr ] * 100
//当 目标点target 取出的 attr 的值 不为opacity 时,target = attr_options[ attr ]
target : attr === "opacity" ? attr_options[ attr ] * 100 : attr_options[ attr ],
//元素当前的属性值 ;
//元素属性值取值
//当 元素属性值iNow 取出的 attr 的值 为opacity 时, iNow = parseInt( getComputedStyle(ele)[attr] * 100 )
//当 元素属性值iNow 取出的 attr 的值 不为opacity 时, iNow = parseInt( getComputedStyle(ele)[attr] )
//getComputedStyle(ele)[attr] * 100-------->提取ele元素中 的该元素 ele.attr*100 的结果
iNow : attr === "opacity" ? parseInt( getComputedStyle(ele)[attr] * 100 ) : parseInt( getComputedStyle(ele)[attr] )
}
}
//把所有的定时器都放进ele对象之中;
//关闭计时器
clearInterval(ele.timer);
ele.timer = setInterval(function(){
//遍历attr_option结构数组
//获取速度
for( var attr in attr_options ){
//创建一个参数存放属性名attr_option[attr]结构
var item = attr_options[ attr ];
//创建一个参数存放目标点
var target = item.target;
//创建一个参数存放元素当前的属性值
var iNow = item.iNow;
//运动所必须的值我们都有了;
//运动速度的求取 = 目标点 - 元素当前的属性值
//根据目标点求得运动的速度;
var speed = ( target - iNow ) / 10;
//速度取整
//速度取整; 要查看速度是正数还是负数;
//如果大于0,Math.ceil( speed )--------向上取整
//如果小于0,Math.floor( speed )--------向下取整
speed = speed > 0 ? Math.ceil( speed ) : Math.floor( speed )
//终止条件
//通过终止条件,中止计时器
//根据 target 和当前的元素位置判定速度为正数还是负数
if( Math.abs(target - iNow) <= Math.abs( speed )){
// 终止条件不可靠,因为目标的不一致会让运动次数执行不同,有可能提前关闭定时器;
ele.style[attr] = attr === "opacity" ? target / 100 : target + "px";
// 一条运动完成删除对象里面的数据;
delete attr_options[ attr ];
// 如果对象里面没有属性了,那么我们关闭定时器就可以了;
//遍历attr_options结构数组
for( var num in attr_options){
// 如果attr_options里面有属性,那么此时我就不应该终止定时器;
return false;
}
//关闭计时器
clearInterval( ele.timer );
//判断callback类型
//如果callback的类型为函数,则执行callback
//如果callback的类型不为函数,则执行“”(为空)
typeof callback === "function" ? callback() : "";
}else{
//元素运动
//因为 iNow 是一个临时变量,所以不能再去操作iNow , 要去操作iNow 的数据源;
attr_options[ attr ].iNow += speed;
ele.style[attr] = attr === "opacity" ? attr_options[attr].iNow / 100 : attr_options[attr].iNow + "px";
}
}
},30)
}
全部代码
<!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>
<style>
.box{
width: 80%;
height: 600px;
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>
</head>
<body>
<div class="box"></div>
<script src="animate.js"></script>
<script>
// OOA
// 1. 创建元素;
// 2. 元素运动;
// 3. 烟花爆炸;
// 4. 随机位置;
// 5. 随机颜色;
//OOD
function FireWork( x , y , selector , BZ_type){
//因为要有一个装 创建出来的 火花的盒子 ,所以需要创建一个父级参数selector
// this.main = document.querySelector(selector);
// 每次调用FireWork 都会进行元素选择,会导致元素选择次数太多;
// 向Firework上存储数据;
// 做一个逻辑 : 如果 FireWork上已经有选择好的元素了,那么我们就不需要重复进行选择了
// 1. 如果已经选择过元素了,并且元素上的选择器和传入的选择器
// 单例模式的思想;
//如果 存在FireWork.main 并且 FireWork.main.selector === selector 的挂
if( FireWork.main && FireWork.main.selector === selector){
//由于已经经历过元素,就可以对需要的元素塑性进行直接赋值
this.main = FireWork.main.ele;
// console.log("已经经历过元素原则了,对需要属性进行直接赋值")
}else{
//如果没有的话
//就代表没有选择过元素,现在需要对元素进行选择
// console.log("还没有选择过元素,现在需要进行元素选择")
//????
FireWork.main = {
ele : document.querySelector( selector ),
selector : selector
}
this.main = FireWork.main.ele ;
}
//调用初始化函数,初始化数据
this.init( x , y);
//代表爆炸后呈现的的样式
this.BZ_type = BZ_type;
}
//创建一个原型对象
FireWork.prototype = {
//固定单词 constructor,用来替代构造函数;
constructor : FireWork,
//初始化
init : function( x , y ){
//因为元素要运动,所以要初始化x,y坐标
//把初始化出来的x,y坐标指向this
//这里的this指向FireWork实例对象
this.x = x;
this.y = y;
console.log(this,this.x,this.y,x,y);
//因为要有火花,所以要创建元素
//又因为有了创建函数,所以调用函数FireWorkCJ()
this.ele = this.FireWorkCJ();
console.log(this.ele);
// 为了节省randomBoundary消耗的无用性能,统一获取一次left和top的最大值;
// 注意程序的执行顺序, 元素的offset属性获取,必须要放在元素插入到页面之后才行;
this.left_max = this.main.offsetWidth - this.ele.offsetWidth;
this.top_max = this.main.offsetHeight - this.ele.offsetHeight;
//给元素添加背景颜色
this.FireWorkYS( this.ele );
// 烟花主体升起;
this.FireWorkYD( this.ele );
},
//1.创建元素
// 什么时候要使用var 什么时候要使用 this.xxx ;
// 如果这个数据在其他的方法里还要用,那么就放在this之中;
// 如果感觉这个变量在当前函数使用结束就不用了,那么就用var;
FireWorkCJ : function(){
//首先要创建一个火花的盒子
var ele = document.createElement("div");
//让他拥有className,成为拥有该样式的盒子
ele.className = "fire";
//将这个火花盒子放到父级
//由于传入了父级参数 selector ,将创建出来的 ele 放到父级
this.main.appendchild( ele );
//返回ele
return ele;
},
//2.元素运动
FireWorkYD : function( ele ){
//创建元素的左右位置
//left : 直接到达
//top : 运动到达目的地
//创建的元素 ele 的left为 this.x 的位置像素
ele.style.left = this.x + "px";
//调用运动函数
animate( ele ,{
top : this.y
},function(){
// 烟花运动结束要删除掉这个元素;
ele.remove();
// 直接调用烟花爆炸功能;
this.FireWorkBZ();
}.bind(this))
},
//3.烟花爆炸
FireWorkBZ : function(){
//烟花爆炸,随机生成多个(20)个火花
for( var i = 0 ; i < 20 ; i++){
//创建火花
var ele = this.FireWorkCJ();
this.FireWorkYS( ele );
//初始化火花的样式
ele.style.left = this.x + "px";
ele.style.top = this.y + "px";
ele.style.borderRadius = "50%";
//让元素有运动目标;
animate( ele , this.BZ_type = "circular" ? this.BZ_YUAN( i , 20 ) : this.FireWorkWZ() , function( callback_ele ){
// 什么时候会执行这个回调函数; 一定的时间之后; for循环早就执行完了;
// 在这个作用域之中ele只有一个,当你执行回调函数的时候,ele已经被赋值20次了,ele里面的数据之后最后一个。
// bind 的高级用法;
callback_ele.remove();
}.bind(this , ele))
// 因为执行了20次,会创造20个不同的函数;
// 现在给每个匿名函数都去绑定一个ele元素;
// function( ele ){ ele => ele1 }.bind(this,ele1)
// function( ele ){ ele => ele2 }.bind(this,ele2)
// function( ele ){ ele => ele3 }.bind(this,ele3)
// ...
}
},
//4.随机位置6
FireWorkWZ : function(){
return {
left : parseInt( Math.random() * ( this.left_max + 1) ),
top : parseInt( Math.random() * ( this.top_max + 1) )
}
},
//5.随机颜色
//给已经创建出来的ele火花盒子添加随机颜色样式
FireWorkYS : function( ele ){
return ele.style.backgroundColor = "#" + parseInt( parseInt( "ffffff" , 16) * Math.random() ).toString(16).padStart( 6 , 0 );
},
//6.扩展:爆炸后呈圆形绽放
//now_index : 代表这是创建的第几个圆
//total : 代表 一共要创建多少个
BZ_YUAN : function( now_index , total ){
var r = 100;
// 计算角度;
//reg : 代表第i个对应的角度
var reg = (360 / total ) * now_index;
// JS里面没有角度只有弧度; 换算弧度;
//deg : 转化成弧度
var deg = Math.PI / 180 * reg;
return {
left : parseInt(r * Math.cos( deg )) + this.x,
top : parseInt(r * Math.sin( deg )) + this.y,
}
}
}
// new FireWork( 200,200,".box");
document.querySelector(".box").addEventListener("click",function( evt ){
var e = evt || event;
new FireWork(e.offsetX , e.offsetY , ".box" , "circular")
})
</script>
</body>
</html>