炎炎夏日,快用代码下场雨ヽ`☂ヽ`canvas
发布日期:2021-05-07 18:24:15 浏览次数:22 分类:原创文章

本文共 14028 字,大约阅读时间需要 46 分钟。

一.先看效果(源码在最后):

哗啦啦啦


图片展示,因为图片限制5m大小,所以演示不太多:
在这里插入图片描述

二.实现过程(可一步一步实现):

因为雨是重点,所以中间 logo 部分就不详细写了,可直接看源码~

1.定义canvas标签与设置css基本样式:

 <canvas id="canvas"></canvas>
      *{               margin: 0;            padding: 0;            box-sizing: border-box;        }             #canvas{              position: fixed;           background-color: rgb(0, 0, 0);           z-index: -10;        }

position: fixed; 固定定位。

2. 开始js部分,获取画布与定义基本变量:

 // 获取画布        var canvas = document.querySelector("#canvas");        var rain = canvas.getContext('2d');        // drop数组,存每个散开的小水滴信息        var drop = [];        // water数组,存每丝雨的信息        var water = [];        // 雨的数量,可自行更改        var waterNum = 100;        // 小水(雨)滴的重力        var gravity = 1;        // 鼠标在页面的初始位置        var mouseX=-36,mouseY=-36;        // 关于雨的角度值,值为-1到1,后面讲        var direction = 0;        // 这也是关于鼠标在页面位置的角度值,值为-1到1        var mouseDelay = 0;        // 这是画布自适应窗口大小的函数,复制即可        window.onresize = resizeCanvas;            function resizeCanvas() {                   canvas.width = window.innerWidth;                canvas.height = window.innerHeight;            }            resizeCanvas();

2.初始化雨:

  // 一丝雨的初始化,封装,后面好几处要调用        function creatWater(){                            water.push({                       //值为0或1,判断是否要散开水滴                    add:1,                    //随机初始水平位置                    x:Math.random()*3*canvas.width-canvas.width,                    // 随机初始垂直位置,在上面一点,这样雨能从上面下落                    y: Math.random()*500-500,                    // 随机雨的长度                    len: Math.random()*20+50,                    // 随机雨的速度                    speed: Math.random()*10+35,                    // 随机雨的随机颜色                    color: `rgb(255,255,255,${     Math.random()*0.5})`,                    // 随机散开水滴数量                    dropNum:Math.random()*6+6                })                           }        // 雨数组初始化,每丝雨都来        function chushi(){               for (let i = 0; i < waterNum; i++) {                  creatWater();            }         }

3.初始化雨滴:

 // 散开水滴数组初始化,x为水平位置,y为垂直位置,dropNum为数量        function creatDrop (x,y,dropNum){               //给drop数组添加元素            for (let j = 0; j < dropNum; j++) {                   drop.push({                       // x轴位置                    pagex:x,                    // y轴位置                    pagey:y,                    // x轴移动距离                    dx:Math.random()*12-6,                    // y轴移动距离                    dy:Math.random()*10-20,                    // 半径                    r:Math.random()+2,                    //颜色                    color: `rgb(255,255,255,${     Math.random()*0.5+0.5})`,                })            }        }

4.绘画每一丝雨:

 // 绘画,画雨        function drawWater(){               //遍历数组            for (let i = 0; i < water.length; i++){                   let temp = water[i];                // 颜色                rain.strokeStyle = temp.color;                // 开始路径                rain.beginPath();                // 开始点                rain.moveTo(temp.x,temp.y);                // 结束点,连线,如: 当前x位置+长度*角度值                  rain.lineTo(temp.x+temp.len*direction,temp.y+temp.len);                // 线宽度                rain.lineWidth = 3;                // 绘制                rain.stroke();                                        }        }

5.绘画每一个雨滴:

 // 绘画雨滴       function drawDrop(){              //遍历        for (let i = 0; i < drop.length; i++){                 let temp = drop[i];            // 线宽度            rain.lineWidth = 2;            //颜色            rain.strokeStyle = temp.color;            //开始路径            rain.beginPath();            // 画一个随机的弧度            rain.arc(temp.pagex,temp.pagey,temp.r, Math.PI , Math.random() * 2 * Math.PI);            // 绘制            rain.stroke();            //结束路径            rain.closePath();                                   }    }

5. 雨信息更新,同时判断各种事件:

 //雨信息的更新       function updateWater(){            for (let i = 0; i < water.length; i++){               // 判断雨的底部是否碰到鼠标,碰到就散开成水滴,x轴y轴与鼠标的位置绝对值在35之内则散开。            if(Math.abs(mouseX-water[i].x)<35&&Math.abs(mouseY-water[i].y-water[i].len)<35){                   // 创建雨滴,传入x轴y轴大小与数量                creatDrop(water[i].x,water[i].y+water[i].len,water[i].dropNum);                // 既然水滴散开了,就清除掉这丝雨                water.splice(i,1);                // 重新来一丝随机的雨                creatWater();            }             // 判断雨的底部是否超过画布底部,且add值为1            if(((water[i].y+water[i].len)>=canvas.height) && water[i].add==1){                  // add值为0                water[i].add = 0;              // 创建雨滴,传入x轴y轴大小与数量,y轴位置就为画布高即可               creatDrop(water[i].x,canvas.height,water[i].dropNum);           }            // 判断整丝雨是否超过画布            if(water[i].y>canvas.height){                   // 清除它               water.splice(i,1);               // 来个新的              creatWater();           }           // 缓动动画原理,雨角度慢慢接近鼠标的角度           direction += (mouseDelay - direction)*0.0002;                      // 雨x轴位置改变           water[i].x += water[i].speed*direction;           //雨y轴位置改变           water[i].y += water[i].speed;                  }       }

6. 雨滴信息更新:

 // 雨滴信息更新       function updateDrop(){              for(let i=0;i<drop.length;i++){               // y轴移动距离加上重力。因为dy一开是负数,所以雨滴先升后降            drop[i].dy +=  gravity;                // x轴位置改变,同时它也受雨角度影响                 drop[i].pagex += drop[i].dx + direction*10;                 // y轴位置改变                 drop[i].pagey += drop[i].dy;                 //判断雨滴是否超过画布                 if(drop[i].pagey>canvas.height){                        //清除水滴                     drop.splice(i,1);                 }           }       }

7.绑定鼠标事件:

 // 绑定鼠标移动事件       window.addEventListener('mousemove',e=>{              // 得到x轴位置              mouseX = e.clientX;              //得到y轴位置              mouseY = e.clientY;              // 雨角度值,在-1到1之间              mouseDelay = (e.clientX-canvas.offsetWidth/2)/(canvas.offsetWidth/2);                     })       // 判断鼠标离开事件       window.addEventListener('mouseout',()=>{              // 给个值,不会产生雨滴的值就行           mouseY=canvas.height+40;       })

8.设置定时器,开始下雨动画:

// 先初始化雨数组       chushi();       //设置定时器,开始动画       setInterval(function(){              // 清除画布          rain.clearRect(0,0,canvas.width,canvas.height);          // 更新雨和雨滴信息          updateWater();             updateDrop();          // 绘画雨和雨滴          drawWater();          drawDrop();       },20)

三.完整代码:

<!DOCTYPE html><html lang="zh-CN"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>北极光之夜。</title>    <style>        *{                margin: 0;            padding: 0;            box-sizing: border-box;        }             #canvas{               position: fixed;           background-color: rgb(0, 0, 0);           z-index: -10;        }        svg{                position: absolute;            top: 50%;            left: 50%;            transform: translate(-50%,-50%);        }        .txt{                   font-family: 'fangsong';            font-weight: 900;            font-size: 80px;            letter-spacing: 3px;            fill: transparent;            stroke: rgb(30, 134, 252);             stroke-width: 1.5px;            stroke-dasharray: 625;            stroke-dashoffset: 625;            animation: draw 2s linear infinite;            text-shadow: 0 0 10px rgb(30, 134, 252),            0 0 20px rgb(30, 134, 252),            0 0 40px rgb(30, 134, 252),            0 0 60px rgb(30, 134, 252);        }        @keyframes draw{                0%,100%{                    stroke-dasharray: 625;                stroke-dashoffset: 625;            }            45%,55%{                    stroke-dasharray: 652;                stroke-dashoffset: 0;            }        }    </style></head><body>    <svg width="500" height="200">        <text x="30" y="120" class="txt">北极光之夜。</text>  </svg>       <canvas id="canvas"></canvas>    <script>        // 获取画布        var canvas = document.querySelector("#canvas");        var rain = canvas.getContext('2d');        // drop数组,存每个散开的小水滴信息        var drop = [];        // water数组,存每丝雨的信息        var water = [];        // 雨的数量,可自行更改        var waterNum = 100;        // 小水(雨)滴的重力        var gravity = 1;        // 鼠标在页面的初始位置        var mouseX=-36,mouseY=-36;        // 关于雨的角度值,值为-1到1,后面讲        var direction = 0;        // 这也是关于鼠标在页面位置的角度值,值为-1到1        var mouseDelay = 0;        // 这是画布自适应窗口大小的函数,复制即可        window.onresize = resizeCanvas;            function resizeCanvas() {                    canvas.width = window.innerWidth;                canvas.height = window.innerHeight;            }            resizeCanvas();               // 一丝雨的初始化,封装,后面好几处要调用        function creatWater(){                             water.push({                        //值为0或1,判断是否要散开水滴                    add:1,                    //随机初始水平位置                    x:Math.random()*3*canvas.width-canvas.width,                    // 随机初始垂直位置,在上面一点,这样雨能从上面下落                    y: Math.random()*500-500,                    // 随机雨的长度                    len: Math.random()*20+50,                    // 随机雨的速度                    speed: Math.random()*10+35,                    // 随机雨的随机颜色                    color: `rgb(255,255,255,${      Math.random()*0.5})`,                    // 随机散开水滴数量                    dropNum:Math.random()*6+6                })                           }        // 雨数组初始化,每丝雨都来        function chushi(){                for (let i = 0; i < waterNum; i++) {                   creatWater();            }         }       // 散开水滴数组初始化,x为水平位置,y为垂直位置,dropNum为数量        function creatDrop (x,y,dropNum){                //给drop数组添加元素            for (let j = 0; j < dropNum; j++) {                    drop.push({                        // x轴位置                    pagex:x,                    // y轴位置                    pagey:y,                    // x轴移动距离                    dx:Math.random()*12-6,                    // y轴移动距离                    dy:Math.random()*10-20,                    // 半径                    r:Math.random()+2,                    //颜色                    color: `rgb(255,255,255,${      Math.random()*0.5+0.5})`,                })            }        }        // 绘画,画雨        function drawWater(){                //遍历数组            for (let i = 0; i < water.length; i++){                    let temp = water[i];                // 颜色                rain.strokeStyle = temp.color;                // 开始路径                rain.beginPath();                // 开始点                rain.moveTo(temp.x,temp.y);                // 结束点,连线,如: 当前x位置+长度*角度值                  rain.lineTo(temp.x+temp.len*direction,temp.y+temp.len);                // 线宽度                rain.lineWidth = 3;                // 绘制                rain.stroke();                                        }        }      // 绘画雨滴       function drawDrop(){               //遍历        for (let i = 0; i < drop.length; i++){                  let temp = drop[i];            // 线宽度            rain.lineWidth = 2;            //颜色            rain.strokeStyle = temp.color;            //开始路径            rain.beginPath();            // 画一个随机的弧度            rain.arc(temp.pagex,temp.pagey,temp.r, Math.PI , Math.random() * 2 * Math.PI);            // 绘制            rain.stroke();            //结束路径            rain.closePath();                                   }    }      //雨信息的更新       function updateWater(){             for (let i = 0; i < water.length; i++){                // 判断雨的底部是否碰到鼠标,碰到就散开成水滴,x轴y轴与鼠标的位置绝对值在35之内则散开。            if(Math.abs(mouseX-water[i].x)<35&&Math.abs(mouseY-water[i].y-water[i].len)<35){                    // 创建雨滴,传入x轴y轴大小与数量                creatDrop(water[i].x,water[i].y+water[i].len,water[i].dropNum);                // 既然水滴散开了,就清除掉这丝雨                water.splice(i,1);                // 重新来一丝随机的雨                creatWater();            }             // 判断雨的底部是否超过画布底部,且add值为1            if(((water[i].y+water[i].len)>=canvas.height) && water[i].add==1){                   // add值为0                water[i].add = 0;              // 创建雨滴,传入x轴y轴大小与数量,y轴位置就为画布高即可               creatDrop(water[i].x,canvas.height,water[i].dropNum);           }            // 判断整丝雨是否超过画布            if(water[i].y>canvas.height){                    // 清除它               water.splice(i,1);               // 来个新的              creatWater();           }           // 缓动动画原理,雨角度慢慢接近鼠标的角度           direction += (mouseDelay - direction)*0.0002;                      // 雨x轴位置改变           water[i].x += water[i].speed*direction;           //雨y轴位置改变           water[i].y += water[i].speed;                  }       }       // 雨滴信息更新       function updateDrop(){               for(let i=0;i<drop.length;i++){                // y轴移动距离加上重力。因为dy一开是负数,所以雨滴先升后降            drop[i].dy +=  gravity;                // x轴位置改变,同时它也受雨角度影响                 drop[i].pagex += drop[i].dx + direction*10;                 // y轴位置改变                 drop[i].pagey += drop[i].dy;                 //判断雨滴是否超过画布                 if(drop[i].pagey>canvas.height){                         //清除水滴                     drop.splice(i,1);                 }           }       }      // 绑定鼠标移动事件       window.addEventListener('mousemove',e=>{               // 得到x轴位置              mouseX = e.clientX;              //得到y轴位置              mouseY = e.clientY;              // 雨角度值,在-1到1之间              mouseDelay = (e.clientX-canvas.offsetWidth/2)/(canvas.offsetWidth/2);                     })       // 判断鼠标离开事件       window.addEventListener('mouseout',()=>{               // 给个值,不会产生雨滴的值就行           mouseY=canvas.height+40;       })      // 先初始化雨数组       chushi();       //设置定时器,开始动画       setInterval(function(){               // 清除画布          rain.clearRect(0,0,canvas.width,canvas.height);          // 更新雨和雨滴信息          updateWater();             updateDrop();          // 绘画雨和雨滴          drawWater();          drawDrop();       },20)    </script></body></html>

四.总结:

看到这里了,不点个赞再走吗~

在这里插入图片描述

五.其它文章:

其它文章:












…等等

上一篇:文字烟雾效果 html+css+js
下一篇:滑动导航栏效果 html+css+js

发表评论

最新留言

留言是一种美德,欢迎回访!
[***.207.175.100]2025年03月27日 08时23分26秒