Por que document.body é nulo no meu javascript?

132

Aqui está o meu breve documento HTML.

Por que o Console do Chrome está notando este erro:

"TypeError não capturado: não é possível chamar o método 'appendChild' of null"?

<html>
<head>
    <title>Javascript Tests</title>

    <script type="text/javascript">

        var mySpan = document.createElement("span");
        mySpan.innerHTML = "This is my span!";

        mySpan.style.color = "red";
        document.body.appendChild(mySpan);

        alert("Why does the span change after this alert? Not before?");

    </script>
</head>
<body>

</body>
</html>
John Hoffman
fonte
Estou usando o Google Chrome.
John Hoffman

Respostas:

180

O corpo ainda não foi definido neste momento. Em geral, você deseja criar todos os elementos antes de executar o javascript que usa esses elementos. Nesse caso, você tem algum javascript na headseção que usa body. Não é legal.

Você deseja agrupar esse código em um window.onloadmanipulador ou colocá-lo após a <body>tag (conforme mencionado no e-bacho 2.0 ).

<head>
    <title>Javascript Tests</title>

    <script type="text/javascript">
      window.onload = function() {
        var mySpan = document.createElement("span");
        mySpan.innerHTML = "This is my span!";

        mySpan.style.color = "red";
        document.body.appendChild(mySpan);

        alert("Why does the span change after this alert? Not before?");
      }

    </script>
</head>

Veja a demonstração .

Sergio Tulentsev
fonte
1
Obrigado, como assim? Não tenho uma etiqueta corporal?
John Hoffman
5
A página é lida de cima para baixo e o javascript é executado ao longo do caminho. Você tem algum javascript na headseção que está sendo executada. Mas bodyparte do html, talvez, ainda nem tenha sido baixada. Ou é baixado, mas ainda não foi avaliado neste momento. Portanto, ele não existe no DOM.
Sergio Tulentsev 28/03
3
E se você não quiser substituir uma carga existente definida em outro arquivo?
Tom Brito
1
@TomBrito: "ou coloque-o após a <body>tag"
Sergio Tulentsev
1
Um pouco tarde, mas também pode usar addEventListener para anexar o ouvinte à janela, sem substituir os existentes.
Edvilme
36

Seu script está sendo executado antes do body elemento seja carregado.

Existem algumas maneiras de solucionar isso.

  • Agrupe seu código em um retorno de chamada do DOM Load:

    Agrupe sua lógica em um ouvinte de evento para DOMContentLoaded .

    Ao fazer isso, o retorno de chamada será executado quando o bodyelemento for carregado.

    document.addEventListener('DOMContentLoaded', function () {
        // ...
        // Place code here.
        // ...
    });

    Dependendo das suas necessidades, você pode anexar alternativamente um loadouvinte de evento ao windowobjeto:

    window.addEventListener('load', function () {
        // ...
        // Place code here.
        // ...
    });

    Para a diferença entre the DOMContentLoadede loadevents, consulte esta pergunta .

  • Mova a posição do seu <script> elemento e carregue o último JavaScript:

    No momento, seu <script>elemento está sendo carregado no <head>elemento do seu documento. Isso significa que ele será executado antes do bodycarregamento. Os desenvolvedores do Google recomendam mover as <script>tags para o final da sua página, para que todo o conteúdo HTML seja renderizado antes do processamento do JavaScript.

    <!DOCTYPE html>
    <html>
    <head></head>
    <body>
      <p>Some paragraph</p>
      <!-- End of HTML content in the body tag -->
    
      <script>
        <!-- Place your script tags here. -->
      </script>
    </body>
    </html>
Josh Crozier
fonte
2
Eu acho que isso é mais completo e atual do que a resposta aceita.
theUtherSide
8

Adicione seu código ao evento onload. A resposta aceita mostra isso corretamente, no entanto, essa resposta e todas as outras no momento da redação também sugerem colocar a tag de script após a tag de fechamento do corpo,.

Este não é um html válido. No entanto, seu código funcionará, porque os navegadores são muito gentis;)

Veja esta resposta para obter mais informações. É errado colocar a tag <script> após a tag </body>?

Votou outras respostas por esse motivo.

Martin Hansen
fonte
4

Ou adicione esta parte

<script type="text/javascript">

    var mySpan = document.createElement("span");
    mySpan.innerHTML = "This is my span!";

    mySpan.style.color = "red";
    document.body.appendChild(mySpan);

    alert("Why does the span change after this alert? Not before?");

</script>

após o HTML, como:

    <html>
    <head>...</head>
    <body>...</body>
   <script type="text/javascript">
        var mySpan = document.createElement("span");
        mySpan.innerHTML = "This is my span!";

        mySpan.style.color = "red";
        document.body.appendChild(mySpan);

        alert("Why does the span change after this alert? Not before?");

    </script>

    </html>
Boris Bachovski
fonte
1

O navegador analisa seu html de cima para baixo, seu script é executado antes do corpo ser carregado. Para corrigir colocar script após o corpo.

  <html>
  <head>
       <title> Javascript Tests </title> 
  </head>
 <body>
 </body>
  <script type="text/javascript">

    var mySpan = document.createElement("span");
    mySpan.innerHTML = "This is my span!";

    mySpan.style.color = "red";
    document.body.appendChild(mySpan);

    alert("Why does the span change after this alert? Not before?");

</script>
</html>
Emmanuel N
fonte
0

document.body ainda não está disponível quando seu código é executado.

O que você pode fazer:

var docBody=document.getElementsByTagName("body")[0];
docBody.appendChild(mySpan);
Christophe
fonte
@ Jake, você poderia ser mais específico? Algum exemplo de navegador / versão em que não funciona?
Christophe
chrome @ 39 e firefox @ 33
Jake
@ Jake ok, então minha resposta estava correta no momento em que escrevi ;-) Obrigado por me avisar, vou fazer alguns testes e vou postar uma atualização.
Christophe