开发者问题收集

我的功能有什么问题

2017-03-05
79

我不知道为什么它不起作用。如果您提交该行,然后在控制台中使用 console.log ,则 displayWorld() 底部的函数调用可以正常工作。但如果我在代码中调用该函数,它就会中断。

抱歉,这里是错误

Uncaught TypeError: Cannot set property 'innerHTML' of null at displayWorld (index.html:40) at index.html:43

HTML

<!DOCTYPE html>
<html>
<head>
    <title>Pacman Demo</title>
    <meta charset="utf-8">
  <link rel="stylesheet" type="text/css" href="style.css"></style>
  <script type="text/javascript" src='http://code.jquery.com/jquery-1.10.2.min.js'></script> 
  <script type="text/javascript">

  var world = [
              [2,2,2,2,2,2,2,2,2,2],
              [2,1,1,2,1,1,1,1,1,2],
              [2,1,1,2,1,2,2,2,1,2],
              [2,1,1,1,1,1,2,1,1,2],
              [2,1,1,1,1,1,2,1,1,2],
              [2,1,1,1,1,1,2,1,1,2],
              [2,1,1,1,1,1,2,1,1,2],
              [2,1,1,1,1,1,1,1,1,2],
              [2,2,2,2,2,2,2,2,2,2],

            ];


            function displayWorld(){
                var output = '';

                for(var i=0; i<world.length; i++){
                    output += "\n<div class='row'>";
                    for(var j=0; j<world[i].length; j++){
                        if(world[i][j] == 2)
                            output += "\n\t<div class='brick'></div>";
                        else if(world[i][j] == 1)
                            output += "\n\t<div class='coin'></div>";
                        if(world[i][j] == 0)
                            output += "<\n\tdiv class='empty'></div>";
                    }
                    output += "\n</div>";
                }
                console.log(output);
                document.getElementById('world').innerHTML = output;
            }

     displayWorld();      <----- this piece here
  </script>


    </style>
</head>
<body>

    <div id='world'></div>


</body>
</html>

CSS

/*CSS reset settings here*/
*{
 margin: 0px;
 padding: 0px;
}

body{
    background-color: black ;
}
div.row div{
    width: 20px;
    height: 20px;
    display: inline-block;
}

div.brick {
    background-color: blue;

}

div.coin{
    background: url(coin.gif);
    background-repeat: no-repeat;
    background-position: center;

}

div.packman{
    background: url(mrpacman.gif);
    background-repeat: no-repeat;
    background-position: center;

}

div.empty{


}
2个回答

我认为这是因为您在创建 div 标签之前加载了 js 文件,将脚本放在 body 的末尾,这样就可以解决问题

Mauricio Ortiz
2017-03-05

要完全理解为什么会发生这种情况,您应该了解 HTML + CSS + JS 模型的工作原理。我描述了完整的页面加载和执行逻辑,因为它可能有助于您理解类似的问题。如果您只对当前错误感兴趣,请跳至第 3 点。

  1. 在构建 CSSOM 之前不会执行任何 JavaScript (以防止 FOUC )。
  2. 在读取和解析 <head> 之后构建 CSSOM。 这就是为什么您需要将所有样式表和 <style> 标签放在 <head> 中的原因。如果您将它们放在 <body> 中,则 FOUC 可以在 body 中 <style> 之前的内容上使用,因为它首先是在没有这些规则的情况下呈现的。
  3. <script> 标签一经遇到,就会按出现的顺序读取和执行。已经从 <head> 加载的标签在 <body> 标签添加到 DOM 之前按遇到的顺序执行。 <body> 内的 <script> 标签在构建 DOM 时满足条件时执行, 但在页面其余部分(后面的内容)添加到 DOM 之前。

这意味着您的 <script> 标记在 DOM 中创建 <div id="world"></div> 之前执行,并且您的脚本尝试使用此行向其添加内容...

document.getElementById('world').innerHTML = output;

... 会导致错误,因为 document.getElementById('world') 此时返回 null ,而 null 没有 innerHTML 属性。

要修复此问题,您应将脚本放在 <body> 中,位于 #world div 之后:

*{
 margin: 0px;
 padding: 0px;
}

body{
    background-color: black ;
}
div.row div{
    width: 20px;
    height: 20px;
    display: inline-block;
}

div.brick {
    background-color: blue;

}

div.coin{
    background: url(coin.gif);
    background-repeat: no-repeat;
    background-position: center;

}

div.packman{
    background: url(mrpacman.gif);
    background-repeat: no-repeat;
    background-position: center;

}

div.empty{

}
<div id="world"></div>
<script type="text/javascript">
  var world = [
    [2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
    [2, 1, 1, 2, 1, 1, 1, 1, 1, 2],
    [2, 1, 1, 2, 1, 2, 2, 2, 1, 2],
    [2, 1, 1, 1, 1, 1, 2, 1, 1, 2],
    [2, 1, 1, 1, 1, 1, 2, 1, 1, 2],
    [2, 1, 1, 1, 1, 1, 2, 1, 1, 2],
    [2, 1, 1, 1, 1, 1, 2, 1, 1, 2],
    [2, 1, 1, 1, 1, 1, 1, 1, 1, 2],
    [2, 2, 2, 2, 2, 2, 2, 2, 2, 2],

];

function displayWorld() {
    var output = '';

    for (var i = 0; i < world.length; i++) {
        output += "\n<div class='row'>";
        for (var j = 0; j < world[i].length; j++) {
            if (world[i][j] == 2)
                output += "\n\t<div class='brick'></div>";
            else if (world[i][j] == 1)
                output += "\n\t<div class='coin'></div>";
            if (world[i][j] == 0)
                output += "<\n\tdiv class='empty'></div>";
        }
        output += "\n</div>";
    }
    document.getElementById('world').innerHTML = output;
}

displayWorld();
  </script>

或者,您可以通过将脚本包装在内部来延迟其执行

window.onload = function() {
  // your script here...
}

这将延迟脚本的执行,直到为 window 触发 load 事件,该事件在遇到 </html> 并且 DOM 完成后立即发生。

注意: 您的脚本不包含任何 jQuery 代码,并且由于您的示例不需要它,因此我将其删除。

tao
2017-03-05