Почему в моем javascript указано значение null для document.body?

132

Вот мой краткий HTML-документ.

Почему консоль Chrome отмечает эту ошибку:

«Uncaught TypeError: невозможно вызвать метод appendChild из 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>
Джон Хоффман
источник
Я использую Google Chrome.
Джон Хоффман,

Ответы:

180

Тело еще не определено. В общем, вы хотите создать все элементы, прежде чем выполнять javascript, который использует эти элементы. В этом случае у вас есть некоторый javascript в headразделе, который использует body. Не круто.

Вы хотите , чтобы обернуть этот код в window.onloadобработчик или поместить его после того, как в <body>теге (как уже упоминалось электронной 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>

См. Демо .

Серхио Туленцев
источник
1
Спасибо, что вы имеете в виду? У меня нет тега на теле?
Джон Хоффман,
5
Страница читается сверху вниз, а javascript выполняется по ходу. У вас есть JavaScript в headисполняемом разделе. Но bodyчасть html, может быть, еще даже не скачана. Или он загружен, но на данный момент еще не оценивается. Так что его нет в DOM.
Серджио Туленцев,
3
Что, если вы не хотите переопределять существующую загрузку, определенную в другом файле?
Том Брито
1
@TomBrito: «или поместить его после того, как в <body>теге»
Серхио Tulentsev
1
Немного поздно, но можно также использовать addEventListener для прикрепления слушателя к окну без замены существующих.
Эдвилме
36

Ваш скрипт выполняется еще до bodyзагрузки элемента.

Есть несколько способов обойти это.

  • Оберните свой код в обратный вызов DOM Load:

    Оберните свою логику в прослушиватель событий для DOMContentLoaded.

    При этом обратный вызов будет выполнен после bodyзагрузки элемента.

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

    В зависимости от ваших потребностей вы можете также прикрепить load к windowобъекту прослушиватель событий :

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

    Для разницы между DOMContentLoaded и loadсобытиями, увидеть этот вопрос .

  • Переместите позицию вашего <script>элемента и загрузите JavaScript последней:

    Прямо сейчас ваш <script>элемент загружается в <head>элемент вашего документа. Это означает, что он будет выполнен до того, bodyкак загрузится. Разработчики Google рекомендуют переместить <script>теги в конец страницы, чтобы все содержимое HTML отображалось до обработки 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
Я думаю, что это более полный и актуальный ответ, чем принятый ответ.
theUtherSide 06
8

Добавьте свой код в событие onload. Принятый ответ показывает это правильно, однако этот ответ, как и все остальные на момент написания, также предлагает поместить тег скрипта после закрывающего тега тела.

Это недействительный HTML. Однако это заставит ваш код работать, потому что браузеры слишком добрые;)

См. Этот ответ для получения дополнительной информации. Неправильно размещать тег <script> после тега </body>?

По этой причине проголосовали против других ответов.

Мартин Хансен
источник
4

Или добавьте эту часть

<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, например:

    <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

Браузер анализирует ваш html сверху вниз, ваш скрипт запускается до загрузки тела. Чтобы исправить, ставьте скрипт после тела.

  <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 еще не доступен при запуске вашего кода.

Что вы можете сделать вместо этого:

var docBody=document.getElementsByTagName("body")[0];
docBody.appendChild(mySpan);
Christophe
источник
@ Джейк, не могли бы вы уточнить? Любой пример браузера / версии, где он не работает?
Christophe
chrome @ 39 и firefox @ 33
Джейк
@ Джейк, хорошо, поэтому мой ответ был правильным на момент написания ;-) Спасибо, что предупредили меня, я проведу небольшое тестирование и опубликую обновление.
Christophe