当前位置: 首页 > Web前端 > JavaScript

冬天来了,给你的网站下雪吧

时间:2023-03-27 10:40:56 JavaScript

前言这两天闺蜜经常光顾的设计网站页面出现了下雪效果,所以问我网站能不能下雪,作为程序员的我一般都是这么说的做不到,但是作为男朋友,也不能说做不到。SnowSnow我们可以用span标签和css的径向渐变做一个简单的意思:.snow{display:block;宽度:100px;高度:100px;背景图像:径向渐变(#fff0%,rgba(255、255、255、0)60%);border-radius:50%;}效果如下:多雪不够一场雪,千千万万的浪漫,世界上没有两片一模一样的雪花,所以每一场雪都有自己的大小,位置,速度等属性,首先创建一个雪花类:|80//最小直径this.minWidth=opt.minWidth||2//透明度this.opacity=0//水平位置this.x=0//重置位置this.y=0//速度this.speed=0//最大速度this.maxSpeed=opt.maxSpeed||4//最小速度this.minSpeed=opt.minSpeed||1//浏览器窗口大小this.windowWidth=window.innerWidththis.windowHeight=window.innerHeightthis.init()}//初始化各种属性init(){this.width=Math.floor(Math.random()*this.maxWidth+this.minWidth)this.opacity=Math.random()this.x=Math.floor(Math.random()*(this.windowWidth-this.width))this.y=Math.floor(Math.random()*(this.windowHeight-this.width))this.speed=Math.random()*this.maxSpeed+this.minSpeed}//设置样式setStyle(){this.el.style.cssText=`位置:固定;左:0;顶部:0;显示:块;宽度:${this.width}px;高度:${this.width}px;不透明度:${this.opacity};背景图像:径向渐变(#fff0%,rgba(255、255、255、0)60%);边界半径:50%;z-索引:9999999999999;指针事件:无;转换:翻译(${this.x}px,${this.y}px);`}//renderrender(){this.el=document.createElement('div')this.setStyle()document.body.appendChild(this.el)}}init方法用于生成随机初始大小、位置、速度和其他属性,在浏览器窗口中尝试new100个切片:letsnowList=[]for(leti=0;i<100;i++){letsnow=newSnow()snow.render()snowList.push(snow)}效果如下:只有雪在动,才叫下雪。移动很简单,不断改变x和y坐标,在snow类中添加一个移动方法:classsnow{move(){this.x+=this.speedthis.y+=this.speedthis.el.style.left=this.x+'px'this.el.style.top=this.y+'px'}}接下来使用requestAnimationFrame保持刷新:moveSnow(){window.requestAnimationFrame(()=>{snowList.forEach((item)=>{item.move()})moveSnow()})}效果如下,因为速度是正数,所以整个向右倾斜:是的,我看到它动了,但是当我离开屏幕时它就消失了,所以雪会消失,对吧?让雪停下来很简单,检测雪的位置,如果超出屏幕,就让它回到顶部,修改move方法:move(){this.x+=this.speedthis.y+=this.speed//调整完全离开窗口后的初始化方法,还需要修改init方法,因为我们希望它重新出现时y坐标为0或者小于0,这样就不会出现出来了又是稀薄的空气,但是从天而降()}this.el.style.left=this.x+'px'this.el.style.top=this.y+'px'}init(reset){//...this.width=Math.floor(Math.random()*this.maxWidth+this.minWidth)this.y=重置?-this.width:Math.floor(Math.random()*this.windowHeight)//...}所以能源不是下雪了:优化1.水平速度水平速度和垂直速度是一样的,但是看起来有点太斜了,所以调整一下区分水平速度和垂直速度:classSnow{constructor(opt={}){//...//水平速度this.sx=0//垂直速度this.sy=0//...}init(reset){//...this.sy=Math.random()*this.maxSpeed+this.minSpeedthis.sx=this.sy*Math.random()}move(){this.x+=this.sxthis.y+=this.sy//...}}2.左下角没有雪,因为整体向右倾斜,所以左下角大概率不会有雪。这可以通过让雪随机出现在左边来解决:init(reset){//...this.x=Math.floor(Math.random()*(this.windowWidth-this.width))this.y=Math.floor(Math.random()*(this.windowHeight-this.width))if(reset&&Math.random()>0.8){//初始化左边的一小部分雪this.x=-this.width}elseif(reset){this.y=-this.width}//...}3.立即snow随机选取了一点雪,赋予它更大的体积、透明度和速度,然后利用css3的3D透视效果,增加它的z轴值,让它有一种在你眼前掠过的感觉。:classSnow{constructor(opt={}){//...//z轴值this.z=0//快速滑动的最大速度this.quickMaxSpeed=opt.quickMaxSpeed||10//快速滑动的最小速度this.quickMinSpeed=opt.quickMinSpeed||8//快速滑动的宽度this.quickWidth=opt.quickWidth||80//快速滑动的不透明度this.quickOpacity=opt.quickOpacity||0.2//...}init(reset){letisQuick=Math.random()>0.8this.width=isQuick?this.quickWidth:Math.floor(Math.random()*this.maxWidth+this.minWidth)this.z=isQuick?Math.random()*300+200:0this.opacity=isQuick?this.quickOpacity:Math.random()//...this.sy=isQuick?Math.random()*this.quickMaxSpeed+this.quickMinSpeed:Math.random()*this.maxSpeed+this.minSpeed//...}move(){//...this.el.style.transform=`translate3d(${this.x}px,${this.y}px,${this.z}px)`}}4.鹅毛雪花,轻如鹅毛,鹅毛是怎么飘起来的?它是左右浮动的吗?然后我们也可以选择一部分雪,让它像鹅毛一样飘起来。左右摆动很简单,速度可以一会儿增减:classSnow{constructor(opt={}){//...//是否左右摆动this.isSwing=false//左右摆动步长this.stepSx=0.03//...}//随机初始化属性init(reset){//...this.isSwing=Math.random()>0.8//...}move(){if(this.isSwing){if(this.sx>=1||this.sx<=-1){this.stepSx=-this.stepSx}this.sx+=this.stepSx}//...}}除了上述方法,还有一种左右摆动的方法,就是用正弦或余弦函数,因为它们的曲线翻转90度左右摆动:我们用的是正弦函数,公式为:y=sin(x),x的值为弧度表示只要一直增加,y的值用于修改雪花在水平方向的速度变化步长:classSnow{constructor(opt={}){//...//左右摆动this.isSwing=false//左右摆动的正弦函数x变量this.swingRadian=0//左右摆动的正弦x步长this.swingStep=0.01//...}init(reset){//...this.swingStep=0.01*Math.random()}move(){if(this.isSwing){this.swingRadian+=this.swingStepthis.x+=this.sx*Math.sin(this.swingRadian*Math.PI)*0.2}else{这.x+=this.sx}//...}}因为正弦函数y的值从1变为-1,摆幅过大,所以乘以小数点0.2缩小,而我想要范围更小,另一种方法就是不用整条正弦曲线,可以从中截取一个合适的区间大小,比如让x的值在0.9π到1之间。1π前变化:classSnow{constructor(opt={}){//...//左右摆动this.isSwing=false//左右摆动的正弦函数x变量this.swingRadian=1//需要更改为一个中间值//左右摆动的正弦x步长this.swingStep=0.01//...}init(reset){//...this.swingStep=0.01*Math.random()this.swingRadian=Math.random()*(1.1-0.9)+0.9//让它也随机}move(){if(this.isSwing){if(this.swingRadian>1.1||this.swingRadian<0.9){this.swingStep=-this.swingStep}this.swingRadian+=this.swingStepthis.x+=this.sx*Math.sin(this.swingRadian*Math.PI)}else{this.x+=this.sx}//...}}5.减速。既然水平加了曲线,那么垂直方向是不是也可以改成非匀速呢?当然,不同的是速度必须一直为正,否则会出现不自然的现象。改变速度曲线也可以使用正弦和余弦。上面我们使用了0.9π和1.1π之间的正弦曲线。根据上图,我们可以发现对应的余弦曲线都是负的,趋势是先慢后快,所以可以利用这一段来改变垂直方向的速度:move(){if(this.isSwing){如果(this.swingRadian>1.1||this.swingRadian<0.9){this.swingStep=-this.swingStep}this.swingRadian+=this.swingStepthis.x+=this.sx*Math.sin(this.swingRadian*Math.PI)this.y-=this.sy*Math.cos(this.swingRadian*Math.PI)//因为速度是负数,所以改成-}else{this.x+=this.sxthis.y+=this.sy}//...}6.在最上面,防止它是一个更高的元素页面上的层级阻塞,给雪花样式添加一个大层:render(){this.el=document.createElement('div')this.el.style.cssText=`//...z-index:9999999999999;`document.body.appendChild(this.el)}7.看不到我修改了图层,所以雪花会在页面顶部,所以可能会挡住其他元素的鼠标事件,以及需要禁止响应鼠标事件:render(){this.el=document.createElement('div')this.el.style.cssText=`//...pointer-events:none;`document.body.appendChild(this.el)}8.最好为动画使用性能更好的变换属性:render(){this.el=document.createElement('div')this.el.style.cssText=`left:0;顶部:0;变换:翻译(${this.x}px,${this.y}px);`document.body.appendChild(this.el)}move(){//...//this.el.style.left=this.x+'px'//this.el.style.top=this.y+'px'this.el.style.transform=`translate(${this.x}px,${this.y}px)`}当然最好的办法是用canvas画出最终效果:rain&sleet下雪后,下一次会下雨。雨和雪类似,都是从天而降,只是下雨的速度更快,而且通常不会左右摆动。是的,方向基本一致,我们先修改样式:setStyle(){this.el.style.cssText=`//...width:1px;//...`}很简单,设置宽度就写成1即可:接下来去掉摆动:move(){this.x+=this.sxthis.y+=this.sy//...}效果如下:可以发现雨是垂直的,水平的移动显然是不行的。它需要倾斜一定角度以与运动方向保持一致。这也很简单。计算斜率并将水平速度除以垂直速度:move(){//...this.el.style.transform=`translate(${this.x}px,${this.y}px)${this.getRotate(this.sy,this.sx)}`}getRotate(sy,sx){返回`旋转(${sx===0?0:(90+Math.atan(sy/sx)*(180/Math.PI))}deg)`}因为tan(θ)=sy/sx,θ=Math。atan(sy/sx),因为雨的线段默认是从上到下垂直的,θ表示与水平方向的夹角,所以需要先旋转90度,再旋转角度,最后将圆弧转为角度公式为:角度=弧度*(180/π)。下雨下雪都实现了,让他们一起出来,下雪了:把上面的代码放在网站上根据天气下雪就会有下雪的效果,也可以使用天气厂商的API,根据实时天气下雪或下雨时,再实现太阳、乌云等效果,一个沉浸式天气就完成了,有兴趣的可以自行实践。完整代码在https://github.com/wanglin2/snow。