教你用面向对象方法写一个烟花爆炸的特效

由于是面向对象,所以步骤非常重要
**

一.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>
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值