为什么我用序列帧以后不用等图片加载完成再执行也能显示图片,用了onload等图片加载完反而不能显示图片了?

比如我的drawStars()里面要写入一张图片,我用window.requestAnimationFrame的话,就不需要img.onload = function(){}图片就可以直接显示出来,若再用img.onload = function(){}就加载不出来图片了;但是我不用window.requestAnimationFrame,就必须写img.onload = function(){}才能加载出来图片。

而且:我不用window.requestAnimationFrame的话,在img.onload以后写入的图片会出现在canvas (0,0)的位置;但是用window.requestAnimationFrame的话,就能出现在指定的this.x, this.y位置

用window.requestAnimationFrame的代码如下:

<script type="text/javascript">
            var can;
            var ctx;
            var width;
            var height;
            var num = 60;        //星星的数量
            var stars = [];    //定义一个数组
            var girl_img = new Image();        
            var stars_img = new Image();
            
//            requestAnimFrame循环,它会根据浏览器自动设置循环刷新时间
            window.requestAnimFrame = (function() {
                return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
                    function( /* function FrameRequestCallback */ callback, /* DOMElement Element */ element) {
                        return window.setTimeout(callback, 1000 / 60);
                    };
            })();

//            初始化canvas
            function init(){
                can = document.getElementById("canvas");
                ctx = can.getContext("2d");
                width = can.width;
                height = can.height;
                girl_img.src = "../例程/src/girl.jpg";
                stars_img.src = "../例程/src/star.png";
                for(var i=0; i<num; i++){                
                    var obj = new star_obj();    //创建一个实体对象
                    stars.push(obj);            //把对象放入stars数组的最后
                    stars[i].initStars();            //执行star_obj的init方法
                }
                gameLoop();
            }            
            
//            画背景图
            function drawBackground(){
                ctx.fillStyle = "cornflowerblue";
                ctx.fillRect(0,0,width,height);
            }
            
//            插入女孩儿图片
            function drawGirl(){
                //girl_img.onload = function(){                //当drawBackground()没写在gameLoop()里面的时候一定要写这句;当drawBackground()写在gameLoop()里面的时候一定不要写这句;等图片加载完,是girl_img.onload!!!;
                    ctx.drawImage(girl_img,100,150,600,300);
                //}
            }
    
//            序列帧,每个一段时间刷新一下,让图片看起来是动的
            function gameLoop(){
                window.requestAnimationFrame(gameLoop);        //序列帧循环;()里面是回调函数,一直循环自己这个gameLoop函数
                drawBackground();
                drawGirl();
                drawStars();
            }
            
/****************************画很多星星****************************/
//            创建类(类就是一套规则;对一群具有相同特征的对象的集合的描述)
//            function star_obj()
            var star_obj = function(){
                this.x;                    //this是泛指,当用new通过star_obj规则创建一个具体的对象,则this指向那个具体对象
                this.y;
            }
            
//            给类定义一些方法
//            定义init初始化方法
            star_obj.prototype.initStars = function(){
                this.x = Math.floor(Math.random()*601+100);
                this.y = Math.floor(Math.random()*301+150);
            }
            
//            定义draw方法
            star_obj.prototype.draw = function(){                //注意:这里star_obj不能带()!!!
//                stars_img.onload = function(){                    //当drawBackground()没写在gameLoop()里面的时候一定要写这句;当drawBackground()写在gameLoop()里面的时候一定不要写这句;等js里面的stars_img加载完,再写入图片位置
                        ctx.drawImage(stars_img, this.x, this.y);
//                }
            }
            
//            随机生成星星方法
            function drawStars(){
                for(var i=0; i<num; i++){
                        stars[i].draw();
                }
            }        
    
            init();
            
        </script>

显示效果:
图片描述
用img.onload = function(){}的代码如下:


    var can;
            var ctx;
            var width;
            var height;
            var num = 60;        //星星的数量
            var stars = [];    //定义一个数组
            var girl_img = new Image();        
            var stars_img = new Image();
            
//            requestAnimFrame循环,它会根据浏览器自动设置循环刷新时间
            window.requestAnimFrame = (function() {
                return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
                    function( /* function FrameRequestCallback */ callback, /* DOMElement Element */ element) {
                        return window.setTimeout(callback, 1000 / 60);
                    };
            })();

//            初始化canvas
            function init(){
                can = document.getElementById("canvas");
                ctx = can.getContext("2d");
                width = can.width;
                height = can.height;
                girl_img.src = "../例程/src/girl.jpg";
                stars_img.src = "../例程/src/star.png";
                for(var i=0; i<num; i++){                
                    var obj = new star_obj();    //创建一个实体对象
                    stars.push(obj);            //把对象放入stars数组的最后
                    stars[i].initStars();            //执行star_obj的init方法
                }
            }            
            
//            画背景图
            function drawBackground(){
                ctx.fillStyle = "cornflowerblue";
                ctx.fillRect(0,0,width,height);
            }
            
//            插入女孩儿图片
            function drawGirl(){
                girl_img.onload = function(){                //当drawBackground()没写在gameLoop()里面的时候一定要写这句;当drawBackground()写在gameLoop()里面的时候一定不要写这句;等图片加载完,是girl_img.onload!!!;
                    ctx.drawImage(girl_img,100,150,600,300);
                }
            }
    

                
            
/****************************画很多星星****************************/
//            创建类(类就是一套规则;对一群具有相同特征的对象的集合的描述)
//            function star_obj()
            var star_obj = function(){
                this.x;                    //this是泛指,当用new通过star_obj规则创建一个具体的对象,则this指向那个具体对象
                this.y;
            }
            
//            给类定义一些方法
//            定义init初始化方法
            star_obj.prototype.initStars = function(){
                this.x = Math.floor(Math.random()*601+100);
                this.y = Math.floor(Math.random()*301+150);
            }
            
//            定义draw方法
            star_obj.prototype.draw = function(){                //注意:这里star_obj不能带()!!!
                stars_img.onload = function(){                    //当drawBackground()没写在gameLoop()里面的时候一定要写这句;当drawBackground()写在gameLoop()里面的时候一定不要写这句;等js里面的stars_img加载完,再写入图片位置
                        ctx.drawImage(stars_img, this.x, this.y);
                }
            }
            
//            随机生成星星方法
            function drawStars(){
                for(var i=0; i<num; i++){
                        stars[i].draw();
                }
            }        
    
            init();
            drawBackground();
            drawGirl();
            drawStars();

显示效果:
图片描述

我想要的是图1的效果,但是我不用window.requestAnimFrame,用onload等图片加载出来,为什么stars_img显示的不是我让它在的地方呢?还有就是为什么用window.requestAnimFrame就不用onload加载以后再执行之后的程序了,写了onload反而加载不出来了。

阅读 3.4k
2 个回答

draw方法里不需要添加img onload事件,直接像下面这么写即可:

ctx.drawImage(girl_img,100,150,600,300);

最后统一在window.onload里执行逻辑:

window.onload = function() {
    (function draw() {
        init();
        drawBackground();
        //...and so on
        requestAnimationFrame(draw);
    })();
};
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题