使用JavaScript&CSS-无法读取属性'长度'的未定义

Snowfall Animations Using JavaScript & CSS - Cannot read property 'length' of undefined

本文关键字:属性 长度 未定义 读取 JavaScript amp CSS- 使用      更新时间:2023-09-26

计划

我想用JavaScript和CSS制作一个动画,计划是让雪从div的顶部降到底部。简言之,目前我创建了一个div,并添加了几个将使用JavaScript创建的子DOM元素,这些元素将附加到已经创建的父元素。当浏览器窗口发生变化并自动创建时,雪也会堆积起来。该代码是使用OOP完成的,目前它将更改每个新创建的子DOM元素的CSS属性,以增加顶部和左侧的属性(它们都将设置为绝对位置),一旦DOM元素离开屏幕,它将重置并重新开始,只需确保坚持使用我在Object属性中设置的限制。


问题

目前,如果我在setInterval中运行这个方法snow.animate,它说它找不到我将所有创建的子DOM元素推入的数组的长度属性,但如果我console.log()该数组并尝试获取该数组的length,那么它实际上会向我显示length。我在for循环之前和循环内部进行了日志记录,以检查我是否可以获得数组的长度,并且它可以获得它,但在运行setInterval时不能。


问题

我的问题是,我是遗漏了什么,还是只需要制作单独的function,而不使用Object来存储所有的methods

注意-我在动画method中循环了一段时间-我觉得这样做很不舒服。这种做法是安全的还是糟糕的?是否有其他方法可以使用while loop来创建子元素,这些子元素将被推送到数组中,以便在随后的for循环中使用。


演示代码-JSFIDDLE:https://jsfiddle.net/sb9o0t4m/

HTML

<div id="snowglobe"></div>

CSS

body {
  background-color: #000;
    margin: 0;
}
/*---------------Snow Flakes--------------*/
#snowglobe {
    width: 100%;
    min-height: 650px;
    position: relative;
    top: 0;
    left: 0;
    overflow: hidden;
}
#snowglobe .flake {
    position: absolute;
    width: 1px;
    height: 1px;
    color: rgba(255,255,255,0);
    text-shadow: 0 0 20px #fff;
}

JS

var snow = {
    //variables
    width: window.innerWidth,height: 650,flakeCount: 10,
    gravity: 0.7,windSpeed: 20,flakes: [],
    currentFlake: 0,snowGlobe: document.getElementById('snowglobe'),
    //methods
    getRandom: function(min,max){
        return Math.floor(Math.random() * (max - min) + min);
    },
    animate: function(){
        //while loop
        while (this.currentFlake < this.flakeCount){
            var flake = document.createElement('div'),
            newFlake;
            flake.className = "flake";
            flake.style.fontSize = this.getRandom(20,50) + 'px';
            flake.style.top = this.getRandom(0,this.height) + 'px';
            flake.style.left = this.getRandom(0,this.left) + 'px';
            flake.innerHTML = "*";
            newFlake = this.snowGlobe.appendChild(flake);
            //set a speed property to the newflake obj
            newFlake.speed = this.getRandom(1,100);
            this.flakes.push(newFlake);
            this.currentFlake++;
        }
        var flakes = this.flakes;
        //use the array of dom elements
        for(var i = 0; i < flakes.length; i++){
            positionX = false;
            positionY = false;
            //new Y position
            positionY = parseFloat(flakes[i].style.top) + (flakes[i].speed / 100) * this.gravity;
            if(positionY > this.height){
                positionY = 0 - parseInt(flakes[i].style.fontSize);
                positionX = getRandom(0, width);
            }
            //new X position
            if (!positionX) positionX = parseFloat(flakes[i].style.left) + Math.sin(positionY / this.windSpeed);
            if (positionX < -20) positionX = this.width + 20;
            if (positionX > this.width + 20) positionX = -20;
            // Set new position
            flakes[i].style.top = positionX + 'px';
            flakes[i].style.left = positionX + 'px';
        }
    }
}
//check browser window, did it resize?
window.onresize = function(){
    snow.width = window.innerWidth;
    console.log(snow.width);
}
setInterval(snow.animate, 1000/60);
//if you want, coment out the above line and uncoment the one below to see the snow loading
//snow.animate();

提前感谢

问题是this没有设置为正确的对象。有关详细信息,请参阅"此"问题。

你可以这样调用方法:

setTimeout( function(){ snow.animate(); }, 1000/60 );

但最好使用requestAnimationFrame:

var snow = {
    ...
    animate: function() {
        ...
        window.requestAnimationFrame( (function(){ this.animate() }).bind(this) );
    }
}

您可以简单地通过调用snow.animate()来启动动画。

我还随意修复了一些您不会意识到的错误,因为代码无法运行(引用没有thiswidth等)。这是一把最新的小提琴。

我让你的初始化循环保持原样;由于它只运行一次,通常您会将其放在一个单独的方法中,通常是构造函数或初始化方法。这里唯一的缺点是在每个动画帧上检查while条件会产生开销。