原生JS实现雪花特效

时间:2022-12-09 20:25:39

今天在校园招聘上被问到的问题,用JS写出雪花的效果。我打算使用多种方法来试试如何实现雪花。

这是目前按照网上某种思路模仿的第一种雪花,不太好看,但是大致意思清楚。

思路1:该思路直接由JS实现。

  • 雪花对象的定时创建 + 雪花对象的下落方法(包含消失判定)
  • 雪花创建的位置和雪花形状的建立 + 雪花的速度和雪花可能的左右移动和消失

缺点:

  • 不好看
  • 兼容性
  • 雪花方法不好,需要实时检索元素,应该改用数组维持
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style type="text/css">
        body,div{
            margin: 0;
            padding: 0;
        }
        body{
            width: 100%;
            height: 100%;
            background-color: #000;
            overflow: hidden;
        }
        #divCanvas{
            width: 800px;
            height: 800px;
            background: #212123;
        }
    </style>
</head>
<body>
<div id="divCanvas"></div>
</body>
<script type="text/javascript">
    var canvas = document.getElementById("divCanvas");
    var maxWidth = canvas.clientWidth;
    var maxHeight = canvas.clientHeight;

    function Obj() {};
    Obj.prototype.action = function(o) {
        o.style.left = Math.ceil(Math.random() * maxWidth) + "px";
        o.style.top = 0 + "px";
        var speed = 0;
        setInterval(function() {
            if (parseInt(o.style.top) < maxHeight) {
                o.style.top = parseInt(o.style.top) + speed + "px";
                speed += 5;
            } else {
                o.style.display = "none";
            }

        }, 400);
    }

    setInterval(function() {
        var oDiv = document.createElement("div");
        oDiv.style.color = "#fff";
        oDiv.innerHTML = "*";
        oDiv.style.position = "absolute";
        canvas.appendChild(oDiv);
        var obj = new Obj();
        obj.action(oDiv);
    }, 300);


</script>
</html>

思路2:该思路由JS和CSS3共同实现。

  • 雪花对象的创建 + 雪花的方法
  • 用CSS3完善雪花的渐隐和出现动画 + 雪花固定的top值增加

缺点:

  • 依旧没有用数组来维持,比较占内存
  • 不够好看
  • 兼容性
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style type="text/css">
        body,div{
            margin: 0;
            padding: 0;
        }
        body{
            background: #000;
        }
        .snow{
            width: 10px;
            height: 10px;
            border-radius: 50%;
            background: #fff;
            animation: mysnow 20s;
            position: absolute;
        }
        @keyframes mysnow{
            0%{opacity: 0;}
            50%{opacity: 1}
            100%{opacity: 0;}
        }
        #canvas{
            width: 800px;
            height: 800px;
            background: #213123;
        }
    </style>
    <script type="text/javascript">
        window.onload=function(){
            var canvas=document.getElementById("canvas");
            var maxWidth=canvas.clientWidth;
            var maxHeight=canvas.clientHeight;

            function Snow(){};
            Snow.prototype.Move=function(x){
                var speed=Math.ceil(Math.random()*1);
                x.style.top=Math.floor(Math.random()*maxWidth);
                x.style.left=Math.floor(Math.random()*maxHeight);
                setInterval(function(){
                    if(parseInt(x.style.top)<maxHeight){
                        x.style.top=parseInt(x.style.top)+speed+"px";
                    }else{
                        x.style.display="none";
                    }
                },30);

            }
            setInterval(function(){
                var oDiv=document.createElement("div");
                oDiv.className="snow";
                oDiv.style.top=0+"px";
                oDiv.style.left=Math.ceil(Math.random()*maxHeight)+"px";
                canvas.appendChild(oDiv);
                var snow=new Snow();
                snow.Move(oDiv);
            },200);
        };
    </script>
</head>
<body>
<div id="canvas"></div>
</body>
</html>

思路3:使用数组维持雪花对象,在一开始的时候便随机创建好每个雪花的动态属性

原型模式创建的雪花对象 + 雪花方法

优点:数组维持

缺点:

  • 没有用上 window.requestAnimationFrame方法
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>mySnow- oH!!!Sexy!</title>
    <style type="text/css">
        body,div{margin: 0;padding: 0;}
        #curtain{
            width: 1600px;
            height: 800px;
            background-color: #111123;
        }
        .snow{
            width: 10px;
            height: 10px;
            border-radius: 50%;
            background: #fff;
            position: absolute;
            animation: mysnow 10s;
        }
        @keyframes mysnow{
            0%{opacity: 0;}
            50%{opacity: 1;}
            100%{opacity: 0;}
        }
        .empty{
            display: none;
        }
    </style>
    <script type="text/javascript">
        window.onload=function(){
            var $=function(id){return typeof id==="string"?document.getElementById(id):id};
            var curtain=$("curtain");
            var maxWidth=curtain.clientWidth-50;
            var maxHeight=curtain.clientHeight;

            var snowControl=function(){};

            snowControl.prototype={
                Obj:[],
                maxCount:400,
                count:0,
                Prepare:function(){
                    for(var i=0;i<this.maxCount;i++){
                        var o={
                            positionX:Math.ceil(Math.random()*maxWidth),
                            positionY:Math.ceil(Math.random()*50),
                            speed:Math.ceil(Math.random()*5+3),
                            shake:Math.ceil(Math.random()*3)
                        };                  
                        this.Obj.push(o);
                    };
                },
                Init:function(){
                    if(this.Obj!=null){
                        var oDiv=document.createElement("div");
                        oDiv.className="snow";
                        var now=this.Obj.shift();
                        oDiv.style.top=now.positionY+"px";
                        oDiv.style.left=now.positionX+"px";
                        curtain.appendChild(oDiv);
                        this.Move(oDiv,now);
                        ++this.count;
                    }else{
                        return false;
                    }
                },
                Move:function(oDiv,now){
                    var timer=setInterval(function(){
                        if(now.positionX<maxWidth || now.positioY<maxHeight){
                            now.positionY=now.positionY+now.speed;
                            now.positionX=now.positionX+now.shake;
                            oDiv.style.top=now.positionY+"px";
                            oDiv.style.left=now.positionX+"px";
                        }else{
                            now.positionX=Math.ceil(Math.random()*maxWidth);
                            now.positionY=Math.ceil(Math.random()*50);
                        }
                    },30);
                },

                Letsgo:function(){
                    var oThis=this;
                    var gotimer=setInterval(function(){
                        if(oThis.count==oThis.maxCount){
                            clearInterval(gotimer);
                        }else{
                            oThis.Init();
                        }
                    },400);
                }

            };

            var snow=new snowControl();
            snow.Prepare();
            snow.Letsgo();

};
    </script>
</head>
<body>
    <div id="curtain"></div>
</body>
</html>

思路4: 使用canvas来实现雪花特效

待更...