¿Por qué document.body es nulo en mi javascript?

132

Aquí está mi breve documento HTML.

¿Por qué la consola Chrome está notando este error?

"Tipo de error no detectado: ¿No se puede llamar al método 'appendChild' de 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
fuente
Estoy usando Google Chrome.
John Hoffman

Respuestas:

180

El cuerpo aún no se ha definido en este punto. En general, desea crear todos los elementos antes de ejecutar javascript que usa estos elementos. En este caso tienes algunos javascript en la headsección que usa body. No es genial

Desea envolver este código en un window.onloadcontrolador o colocarlo después de la <body>etiqueta (como se menciona en 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>

Ver demo .

Sergio Tulentsev
fuente
1
Gracias a que te refieres ¿No tengo una etiqueta corporal?
John Hoffman
55
La página se lee de arriba a abajo y JavaScript se ejecuta en el camino. Tienes algunos javascript en la headsección que se está ejecutando. Pero bodyparte del html, tal vez, aún no se ha descargado. O se descarga, pero todavía no se evalúa en este momento. Por lo tanto, no existe en el DOM.
Sergio Tulentsev
3
¿Qué sucede si no desea anular una carga existente definida en otro archivo?
Tom Brito
1
@TomBrito: "o colóquelo después de la <body>etiqueta"
Sergio Tulentsev
1
Un poco tarde, pero también podría usar addEventListener para adjuntar el oyente a la ventana, sin reemplazar los existentes.
edvilme
36

Su script se está ejecutando bodyincluso antes de que el elemento se haya cargado.

Hay un par de formas de solucionar esto.

  • Envuelva su código en una devolución de llamada de carga DOM:

    Envuelva su lógica en un oyente de eventos DOMContentLoaded.

    Al hacerlo, la devolución de llamada se ejecutará cuando el bodyelemento se haya cargado.

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

    Dependiendo de sus necesidades, también puede adjuntar un loaddetector de eventos al windowobjeto:

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

    Para la diferencia entre los eventos DOMContentLoadedy load, vea esta pregunta .

  • Mueva la posición de su <script>elemento y cargue JavaScript al final:

    En este momento, su <script>elemento se está cargando en el <head>elemento de su documento. Esto significa que se ejecutará antes de que se bodyhaya cargado. Los desarrolladores de Google recomiendan mover las <script>etiquetas al final de su página para que todo el contenido HTML se procese antes de que se procese 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
fuente
2
Creo que esto es más completo y actual que la respuesta aceptada.
theUtherSide
8

Agregue su código al evento de carga. La respuesta aceptada muestra esto correctamente, sin embargo, esa respuesta, así como todas las demás al momento de escribir, también sugieren colocar la etiqueta del script después de la etiqueta del cuerpo de cierre,.

Esto no es html válido. Sin embargo, hará que su código funcione, porque los navegadores son demasiado amables;)

Consulte esta respuesta para obtener más información. ¿Es incorrecto colocar la etiqueta <script> después de la etiqueta </body>?

Votó otras respuestas por este motivo.

Martin Hansen
fuente
4

O agrega 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>

después del 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
fuente
1

El navegador analiza su html de arriba hacia abajo, su script se ejecuta antes de cargar el cuerpo. Para arreglar poner script después del cuerpo.

  <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
fuente
0

document.body aún no está disponible cuando se ejecuta su código.

Lo que puedes hacer en su lugar:

var docBody=document.getElementsByTagName("body")[0];
docBody.appendChild(mySpan);
Christophe
fuente
@Jake, ¿podrías ser más específico? ¿Algún ejemplo de navegador / versión donde no funciona?
Christophe
Chrome @ 39 y Firefox @ 33
Jake
@Jake ok, entonces mi respuesta fue correcta al momento de escribir ;-) Gracias por alertarme, haré algunas pruebas y publicaré una actualización.
Christophe