Warum ist document.body in meinem Javascript null?

132

Hier ist mein kurzes HTML-Dokument.

Warum bemerkt Chrome Console diesen Fehler:

"Ungefangener TypeError: Methode 'appendChild' von kann nicht aufgerufen werden 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
quelle
Ich verwende Google Chrome.
John Hoffman

Antworten:

180

Der Körper wurde zu diesem Zeitpunkt noch nicht definiert. Im Allgemeinen möchten Sie alle Elemente erstellen, bevor Sie Javascript ausführen, das diese Elemente verwendet. In diesem Fall haben Sie etwas Javascript in dem headAbschnitt, der verwendet body. Nicht cool.

Sie möchten diesen Code in einen window.onloadHandler einbinden oder nach dem <body>Tag platzieren (wie in e-bacho 2.0 erwähnt ).

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

Siehe Demo .

Sergio Tulentsev
quelle
1
Danke, was meinst du? Habe ich kein Body Tag?
John Hoffman
5
Die Seite wird von oben nach unten gelesen und dabei Javascript ausgeführt. Sie haben etwas Javascript in dem headAbschnitt, der ausgeführt wird. Aber bodyvielleicht wurde ein Teil des HTML-Codes noch nicht einmal heruntergeladen. Oder es wird heruntergeladen, aber zu diesem Zeitpunkt noch nicht ausgewertet. Es existiert also nicht im DOM.
Sergio Tulentsev
3
Was ist, wenn Sie einen vorhandenen Onload, der in einer anderen Datei definiert ist, nicht überschreiben möchten?
Tom Brito
1
@ TomBrito: "oder platzieren Sie es nach dem <body>Tag"
Sergio Tulentsev
1
Etwas spät, könnte aber auch addEventListener verwenden, um den Listener an das Fenster anzuhängen, ohne vorhandene zu ersetzen.
Edvilme
36

Ihr Skript wird ausgeführt, bevor das bodyElement überhaupt geladen wurde.

Es gibt verschiedene Möglichkeiten, dies zu umgehen.

  • Wickeln Sie Ihren Code in einen DOM Load-Rückruf ein:

    Wickeln Sie Ihre Logik in einen Ereignis-Listener für DOMContentLoaded.

    Dabei wird der Rückruf ausgeführt, wenn das bodyElement geladen wurde.

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

    Abhängig von Ihren Anforderungen können Sie loaddem windowObjekt alternativ einen Ereignis-Listener hinzufügen:

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

    Informationen zum Unterschied zwischen DOMContentLoadedund und loadfinden Sie in dieser Frage .

  • Verschieben Sie die Position Ihres <script>Elements und laden Sie zuletzt JavaScript:

    Im <script>Moment wird Ihr Element in das <head>Element Ihres Dokuments geladen . Dies bedeutet, dass es ausgeführt wird, bevor das bodygeladen wurde. Google-Entwickler empfehlen, die <script>Tags an das Ende Ihrer Seite zu verschieben, damit der gesamte HTML-Inhalt gerendert wird, bevor das JavaScript verarbeitet wird.

    <!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
quelle
2
Ich denke, das ist gründlicher und aktueller als die akzeptierte Antwort.
theUtherSide
8

Fügen Sie Ihren Code zum Onload-Ereignis hinzu. Die akzeptierte Antwort zeigt dies korrekt an, aber diese Antwort sowie alle anderen zum Zeitpunkt des Schreibens schlagen ebenfalls vor, das Skript-Tag nach dem schließenden Body-Tag zu setzen.

Dies ist kein gültiger HTML-Code. Es wird jedoch dazu führen, dass Ihr Code funktioniert, da die Browser zu freundlich sind;)

Weitere Informationen finden Sie in dieser Antwort. Ist es falsch, das <script> -Tag nach dem </ body> -Tag zu platzieren?

Andere Antworten aus diesem Grund abgelehnt.

Martin Hansen
quelle
4

Oder fügen Sie diesen Teil hinzu

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

nach dem HTML wie:

    <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
quelle
1

Der Browser analysiert Ihren HTML-Code von oben nach unten. Ihr Skript wird ausgeführt, bevor der Text geladen wird. Um das Skript nach dem Text zu korrigieren.

  <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.
quelle
0

document.body ist noch nicht verfügbar, wenn Ihr Code ausgeführt wird.

Was Sie stattdessen tun können:

var docBody=document.getElementsByTagName("body")[0];
docBody.appendChild(mySpan);
Christophe
quelle
@ Jake könnten Sie genauer sein? Gibt es ein Beispiel für einen Browser / eine Version, bei der / der es nicht funktioniert?
Christophe
Chrom @ 39 und Firefox @ 33
Jake
@ Jake ok, meine Antwort war zum Zeitpunkt des Schreibens korrekt ;-) Danke, dass du mich benachrichtigt hast, ich werde einige Tests durchführen und ein Update veröffentlichen.
Christophe