Dlaczego document.body ma wartość null w moim javascript?


136

Oto mój krótki dokument HTML.

Dlaczego konsola Chrome zauważa ten błąd:

„Uncaught TypeError: Cannot call method '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>

Używam Google Chrome.
John Hoffman,

Odpowiedzi:


182

Na tym etapie ciało nie zostało jeszcze zdefiniowane. Ogólnie rzecz biorąc, chcesz utworzyć wszystkie elementy przed wykonaniem javascript, który używa tych elementów. W tym przypadku masz trochę javascript w headsekcji, która używa body. Nie fajnie.

Chcesz zawinąć ten kod w window.onloadprocedurze obsługi lub umieść go po tej <body>zmiennej (jak wspomniano przez 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>

Zobacz demo .


1
Dziękuję, co masz na myśli? Nie mam tagu body?
John Hoffman,

5
Strona jest czytana od góry do dołu i po drodze wykonywany jest javascript. W wykonywanej headsekcji znajduje się skrypt javascript . Ale bodybyć może część html nie została jeszcze nawet pobrana. Lub jest pobierany, ale na tym etapie nadal nie jest oceniany. Więc nie istnieje w DOM.
Sergio Tulentsev

3
Co jeśli nie chcesz zastępować istniejącego obciążenia zdefiniowanego w innym pliku?
Tom Brito

1
@TomBrito: „lub umieścić go po tym <body>tagiem”
Sergio Tulentsev

1
Trochę za późno, ale przydałby się również addEventListener do dołączenia detektora do okna, bez zastępowania istniejących.
edvilme

38

Twój skrypt jest wykonywany przed bodyzaładowaniem elementu.

Istnieje kilka sposobów obejścia tego problemu.

  • Umieść swój kod w wywołaniu zwrotnym DOM Load:

    Umieść swoją logikę w nasłuchiwaniu zdarzeń DOMContentLoaded.

    W ten sposób wywołanie zwrotne zostanie wykonane po bodyzaładowaniu elementu.

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

    W zależności od potrzeb możesz alternatywnie dołączyć loaddo windowobiektu detektor zdarzeń :

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

    Aby poznać różnicę między zdarzeniami DOMContentLoadedi load, zobacz to pytanie .

  • Przenieś pozycję <script>elementu i załaduj JavaScript na końcu:

    W tej chwili twój <script>element jest ładowany do <head>elementu twojego dokumentu. Oznacza to, że zostanie wykonany przed bodyzaładowaniem. Programiści Google zalecają przeniesienie <script>tagów na koniec strony, aby cała zawartość HTML była renderowana przed przetworzeniem kodu 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>
    

2
Myślę, że jest to dokładniejsze i bardziej aktualne niż zaakceptowana odpowiedź.
theUtherSide

8

Dodaj swój kod do zdarzenia onload. Przyjęta odpowiedź pokazuje to poprawnie, jednak ta odpowiedź, podobnie jak wszystkie inne w momencie pisania, sugeruje również umieszczenie tagu script po zamykającym tagu body,.

To nie jest prawidłowy kod HTML. Jednak spowoduje to, że Twój kod będzie działał, ponieważ przeglądarki są zbyt miłe;)

Zobacz tę odpowiedź, aby uzyskać więcej informacji. Czy umieszczanie tagu <script> po tagu </body> jest niewłaściwe?

Z tego powodu inne odpowiedzi zostały odrzucone.


4

Lub dodaj tę część

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

po kodzie HTML, na przykład:

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

1

Przeglądarka analizuje kod HTML od góry do dołu, a skrypt jest uruchamiany przed załadowaniem treści. Aby naprawić wstawianie skryptu po treści.

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

0

document.body nie jest jeszcze dostępny, gdy działa Twój kod.

Co możesz zamiast tego zrobić:

var docBody=document.getElementsByTagName("body")[0];
docBody.appendChild(mySpan);

@Jake, czy mógłbyś być bardziej szczegółowy? Jakikolwiek przykład przeglądarki / wersji, w której to nie działa?
Christophe,

chrome @ 39 i firefox @ 33
Jake

@Jake ok, więc moja odpowiedź była poprawna w momencie pisania ;-) Dzięki za ostrzeżenie, zrobię kilka testów i opublikuję aktualizację.
Christophe
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.