JS-烟花效果

一.需求分析

html结构非常简单
    只要一个烟花背景,其他内容都是动态生成的

JavaScript部分
    1,点击时,生成两个div标签
        一个在点击位置
        一个在烟花背景最下方
        要让下方的烟花 上升到 鼠标点击位置 的div

    2,两个div重合时
        清除两个div
        生成若干个 小烟花
        小烟花,向四周随机运动

    3,当小烟花到达随机位置后,删除小烟花


*********************
html结构非常简单
    只要一个烟花背景,其他内容都是动态生成的

JavaScript部分
    1,点击时,生成两个div标签
        一个在点击位置
        一个在烟花背景最下方
        要让下方的烟花 上升到 鼠标点击位置 的div

    2,两个div重合时
        清除两个div
        生成若干个 小烟花
        小烟花,向四周随机运动

    3,当小烟花到达随机位置后,删除小烟花


步骤总结
    一,给 背景区域标签,添加点击事件
        1,获取点击位置 offsetX  offsetY
        2,设定极值:
            最小是 0 
            最大是 背景区域 宽高
        3,生成 大烟花标签节点
        4,给 大烟花标签节点 设定 class样式
        5,给 大烟花标签节点 设定 随机背景颜色
        6,给 大烟花标签节点 设定 定位
            上方: left x  top y
            下方: left x  bottom 0
        7,通过move()函数,让下方大烟花运动
            move函数,参数1:下方大烟花
            move函数,参数2:top:y
            move函数,参数3:运动终止执行的程序
                (1),清除两个大烟花
                (2),设定随机小烟花数量
                (3),根据随机小烟花数量,通过for循环,来生成小烟花标签节点
                    a,生成定义,小烟花标签节点
                    b,给 小烟花标签节点 添加class样式
                    c,给 小烟花标签节点 添加随机背景颜色
                    d,给 小烟花标签节点 定义原始位置
                            原始位置就是大烟花消失的位置,就是鼠标点击的位置
                    e,生成 小烟花标签节点 随机的运动目标位置
                    f,通过 move() 函数,让 小烟花标签节点 运动至 随机目标位置
                        move函数,参数1:小烟花标签节点
                        move函数,参数2:left:随机x位置 top:随机y位置
                        move函数,参数3:小烟花标签节点运动终止时执行的程序
                            删除小烟花节点

二.html+css+内部js

在这里插入图片描述

三.外部js-最终

class Fire{
    constructor(ele){
        this.ele=ele;
    }


    getEvent(){
        this.ele.addEventListener('click',(e)=>{
            let x=e.offsetX;
            let y=e.offsetY;

            if(x<0){
                x=0;
            }
            if(y<0){
                y=0;
            }

            if(x>this.ele.clientWidth){
                x=this.ele.clientWidth;
            }
            if(y>this.ele.clientHeight){
                y=this.ele.clientHeight;
            }

            // 生成大烟花并设定
            const fire1=document.createElement('p');
            const fire2=document.createElement('p');

            fire1.className='bigFire';
            fire2.className='bigFire';
            
            let color=this.setColor(); 

            fire1.style.backgroundColor=color;
            fire2.style.backgroundColor=color;

            fire1.style.left=x+'px';
            fire1.style.top=y+'px';

            fire2.style.left=x+'px';
            fire2.style.bottom=0+'px';

            fire1.addEventListener('click',(e)=>{
                e.stopPropagation();
            });
            fire2.addEventListener('click',(e)=>{
                e.stopPropagation();
            });

            this.ele.appendChild(fire1);
            this.ele.appendChild(fire2);

            this.move(fire2,{top:y},()=>{
                this.ele.removeChild(fire1);
                this.ele.removeChild(fire2);

                let num=parseInt(Math.random()*(50-20+1)+20);

                for(let i=1;i<=num;i++){
                    const smallFire=document.createElement('p');
                    smallFire.className='smallFire';
                    smallFire.style.backgroundColor=this.setColor();
                    smallFire.style.left=x+'px';
                    smallFire.style.top=y+'px';

                    this.ele.appendChild(smallFire);

                    let randomX=parseInt(Math.random()*((x+150)-(x-150)+1)+(x-150));
                    let randomY=parseInt(Math.random()*((y+150)-(y-150)+1)+(y-150));

                    this.move(smallFire,{left:randomX,top:randomY},(e)=>{
                        this.ele.removeChild(smallFire);
                    });
                }
            });
            
        });

    }


        setColor(){
            let a1=parseInt(Math.random()*256);
            let a2=parseInt(Math.random()*256);
            let a3=parseInt(Math.random()*256);
            return `rgb(${a1},${a2},${a3})`;
        }

         
        move(ele, obj, callback) {
            let time = {};
            for (let type in obj) {
                let oldVal = 0;
                if (type === 'opacity') {
                    oldVal = parseFloat(window.getComputedStyle(ele)[type]) * 100;
                } else {
                    oldVal = parseInt(window.getComputedStyle(ele)[type]);
                }
                time[type] = setInterval(() => {
                    let val = (obj[type] - oldVal) / 10;
                    val = val > 0 ? Math.ceil(val) : Math.floor(val);
                    oldVal += val;
                    if (type === 'opacity') {
                        ele.style[type] = oldVal / 100;
                    } else {
                        ele.style[type] = oldVal + 'px';
                    }
                    if (oldVal == obj[type]) {
                        clearInterval(time[type]);
                        delete (time[type]);
                    }
    
                    if (Object.keys(time) == 0) {
                        callback();
                    }
                }, 10)
    
            }


    }


}

四.外部js-步骤解释

// 生成烟花的构造函数
// 参数1:生成烟花的背景标签区域

class Fire{
    constructor(ele){
        // 存储参数
        this.ele = ele;
    }

    // 定义方法

    // 生成烟花的方法
    getEvent(){
        // 1,获取鼠标点击的坐标
        // 所有的烟花的事件,都是在点击之后生成的
        this.ele.addEventListener('click' , (e)=>{
            // 1,获取坐标,设定极限值
            // 只是点击,不是拖拽,可以直接获取相对于父级div的坐标
            let x = e.offsetX;
            let y = e.offsetY;


            // 设定边界值,点击到边框线时,数值会超出div的显示范围
            // 最小值是 0
            // 最大值是 div的宽高 this.ele.clientWidth
            // 不需要边框线宽度的
            if(x < 0){
                x = 0;
            }

            if(y < 0){
                y = 0;
            }

            if(x > this.ele.clientWidth){
                x = this.ele.clientWidth;
            }

            if(y > this.ele.clientHeight){
                y = this.ele.clientHeight;
            }

            // 2,生成大烟花,并且设定样式

            // 通过节点操作,生成两个标签节点
            const fire1 = document.createElement('p');
            const fire2 = document.createElement('p');

            // 添加大烟花样式
            fire1.className = 'bigFire';
            fire2.className = 'bigFire';

            // 获取随机的颜色,设定为背景颜色
            let color = this.setColor();

            fire1.style.backgroundColor = color;
            fire2.style.backgroundColor = color;

            // 设定定位

            // 大烟花1在上,大烟花2在下
            fire1.style.left = x + 'px';
            fire1.style.top = y + 'px';

            // 下方的烟花,left是实参,靠div下方显示,bottom为0
            fire2.style.left = x + 'px';
            fire2.style.bottom = 0 + 'px';

            // 阻止默认事件
            // 点击生成的p标签,会触发父级的点击事件,也会生成新的大烟花
            // 必须阻止事件的传播 / 阻止冒泡事件
            fire1.addEventListener('click' , (e)=>{
                e.stopPropagation();
            })
            fire2.addEventListener('click' , (e)=>{
                e.stopPropagation();
            })

            // 将大烟花写入页面
            this.ele.appendChild(fire1);
            this.ele.appendChild(fire2);

            // 通过move函数,让下方的大烟花升空
            // 1,让下方的大烟花,上升
            // 是要运动效果完成,不能瞬间完成,应该调用move函数
            // 我们之前,定义的move函数,都是单属性的运动模式
            // 生成小烟花时,运动方式是至少两个属性运动,不能使用单属性move函数
            // 要使用终极版的运动函数
            // 我们不用自己会写,只要会调用就可以了
            // this.move() 终极版运动函数,并且赋值参数
            // 参数1: 执行运动的标签 --- 下方的大烟花
            // 参数2: 运动方式 --- 下方的top 运动至 大烟花的 top 坐标
            this.move(fire2,{top: y} , ()=>{
                // 当运动终止,也就是两个烟花重合了,删除两个烟花
                this.ele.removeChild(fire1);
                this.ele.removeChild(fire2);

                // 生成若干个小烟花
                // 定义小烟花随机数量 随便定义的,目前就来一个20-50试试
                let num = parseInt(Math.random()*(50+1-20)+20);

                // 通过循环,根据随机数量,生成对应的小烟花
                for(let i = 1 ; i <= num ; i++){
                    // 创建小烟花的节点
                    // 这里定义小烟花,可以let,可以是const,不能是var
                    // 当前程序是在循环中,如果使用var,是定义一个变量
                    // 然后对这个变量,反复进行赋值,最终,var 变量中,存储的是最后一个标签,最后一个小烟花
                    // 当执行删除时,循环已经执行结束,所有的小烟花都已经生成
                    // 执行删除,只会删除最后一个小烟花
                    // 必须使用 let 或者 const 每次循环都生成一个独立的变量,来存储数据
                    // 不会发生覆盖存储的效果,是独立存储相同不影响的不同小烟花
                    let smallFire = document.createElement('p');
                    // 添加样式
                    smallFire.className = 'smallFire';
                    // 添加随机背景颜色
                    smallFire.style.backgroundColor = this.setColor();
                    // 定义小烟花的原始位置,就是大烟花消失的位置,就是鼠标点击的位置
                    smallFire.style.left = x + 'px';
                    smallFire.style.top = y + 'px';
                    
                    // 将小烟花,写入到页面
                    this.ele.appendChild(smallFire);

                    // 定义随机坐标 --- 小烟花运动的目标位置
                    // 坐标可以设定范围,鼠标点击,大烟花消失位置 正负150 范围内
                    // 最小值 (x-150) 最大值 (x+150)
                    // 定义随机数值
                    let randomX = parseInt(Math.random()*(x+150+1-(x-150)) + (x-150));
                    let randomY = parseInt(Math.random()*(y+150+1-(y-150)) + (y-150));

                    // 通过this.move()让小烟花运动
                    this.move(smallFire,{left:randomX , top:randomY} , ()=>{
                        // 当运动终止,也就是小烟花到达随机目标位置
                        // 清除小烟花
                        // 不是只删除一次,是每次都会删除
                        // 第一次把最后一个小烟花删除,之后再执行删除最后一个小烟花,会报错
                        this.ele.removeChild(smallFire);
                    })
                }   

            })
        })
    }

    // 随机颜色方法
    setColor() {
        let c1 = parseInt(Math.random() * 256);
        let c2 = parseInt(Math.random() * 256);
        let c3 = parseInt(Math.random() * 256);
        return `rgb(${c1},${c2},${c3})`;
    }

    // move多属性运动函数终极版
    move(ele, obj, callback) {
        let time = {};
        for (let type in obj) {
            let oldVal = 0;
            if (type === 'opacity') {
                oldVal = parseFloat(window.getComputedStyle(ele)[type]) * 100;
            } else {
                oldVal = parseInt(window.getComputedStyle(ele)[type]);
            }
            time[type] = setInterval(() => {
                let val = (obj[type] - oldVal) / 10;
                val = val > 0 ? Math.ceil(val) : Math.floor(val);
                oldVal += val;
                if (type === 'opacity') {
                    ele.style[type] = oldVal / 100;
                } else {
                    ele.style[type] = oldVal + 'px';
                }
                if (oldVal == obj[type]) {
                    clearInterval(time[type]);
                    delete (time[type]);
                }

                if (Object.keys(time) == 0) {
                    callback();
                }
            }, 10)

        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值