Как проверить, готов ли DOM без фреймворка? - PullRequest
56 голосов
/ 12 ноября 2011

Вопрос так похож на миллионы других здесь и в Интернете - Как проверить, загружен ли DOM в Javascript?Но здесь есть одна загвоздка:

  • Без использования фреймворка, такого как jQuery и т. Д .;
  • Не зная, был ли ваш скрипт загружен через статически размещенный тег <script> или через какой-либо другой Javascript.позже, после того как DOM уже загружен.

Можно ли сделать это более или менее надежно и с кросс-браузерной совместимостью?

Добавлено: Позвольте мне уточнить:Я пишу отдельный файл .JS, который может быть включен в произвольные веб-страницы.Я хочу выполнить код ПОСЛЕ DOM был загружен.Но я не знаю КАК мой сценарий будет включен.Это может быть путем размещения тега <script> (в этом случае будут работать традиционные решения onload или DOM-готовность);или он может быть загружен через AJAX или каким-либо другим способом, намного позже, после того, как DOM уже загружен (поэтому ранее упомянутые решения никогда не сработают).

Ответы [ 6 ]

66 голосов
/ 12 ноября 2011

Свойство document.readyState можно использовать для проверки готовности документа:

if(document.readyState === "complete") {
  //Already loaded!
}
else {
  //Add onload or DOMContentLoaded event listeners here: for example,
  window.addEventListener("onload", function () {/* your code here */}, false);
  //or
  //document.addEventListener("DOMContentLoaded", function () {/* code */}, false);
}
10 голосов
/ 12 ноября 2011

Браузеры Firefox, Opera и Webkit имеют событие уровня документа DOMContentLoaded, которое вы можете прослушивать с помощью document.addEventListener("DOMContentLoaded", fn, false).

Сложнее в IE. Что делает jQuery в IE, так это наблюдает onreadystatechange на объекте документа для определенного состояния готовности с резервной копией события document.onload. document.onload срабатывает позже, чем DOM готов (только после завершения загрузки всех изображений), поэтому он используется только как обратная остановка в случае, если более ранние события не работают по какой-либо причине.

Если вы потратите некоторое время на поиск в Google, вы найдете код для этого. Я полагаю, что наиболее проверенный код для этого находится в больших фреймворках, таких как jQuery и YUI, поэтому, даже если я не использую этот фреймворк, я искал в их исходном коде методы.

Вот основная часть исходного кода jQuery 1.6.2 для document.ready():

bindReady: function() {
    if ( readyList ) {
        return;
    }

    readyList = jQuery._Deferred();

    // Catch cases where $(document).ready() is called after the
    // browser event has already occurred.
    if ( document.readyState === "complete" ) {
        // Handle it asynchronously to allow scripts the opportunity to delay ready
        return setTimeout( jQuery.ready, 1 );
    }

    // Mozilla, Opera and webkit nightlies currently support this event
    if ( document.addEventListener ) {
        // Use the handy event callback
        document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );

        // A fallback to window.onload, that will always work
        window.addEventListener( "load", jQuery.ready, false );

    // If IE event model is used
    } else if ( document.attachEvent ) {
        // ensure firing before onload,
        // maybe late but safe also for iframes
        document.attachEvent( "onreadystatechange", DOMContentLoaded );

        // A fallback to window.onload, that will always work
        window.attachEvent( "onload", jQuery.ready );

        // If IE and not a frame
        // continually check to see if the document is ready
        var toplevel = false;

        try {
            toplevel = window.frameElement == null;
        } catch(e) {}

        if ( document.documentElement.doScroll && toplevel ) {
            doScrollCheck();
        }
    }
},
8 голосов
/ 24 апреля 2013

Это работает для всех браузеров и является кратким и кратким:

var execute = function () {
  alert("executing code");  
};

if ( !!(window.addEventListener) )
  window.addEventListener("DOMContentLoaded", execute)
else // MSIE
  window.attachEvent("onload", execute)
8 голосов
/ 12 ноября 2011

Если полагаться на document.readyState в порядке, быстрое и грязное решение с опросом:

(function() {
    var state = document.readyState;
    if(state === 'interactive' || state === 'complete') {
        // do stuff
    }
    else setTimeout(arguments.callee, 100);
})();
4 голосов
/ 29 мая 2016

Событие DOMContentLoaded наступает, когда исходный HTML-документ полностью загружен и проанализирован, не дожидаясь окончания загрузки таблиц стилей, изображений и подкадров. Хорошо, что Chrome, Firefox, IE9, Opera и Safari поддерживают его одинаково

document.addEventListener("DOMContentLoaded", function(event) 
{
    console.log("DOM fully loaded and parsed");
}

ПРИМЕЧАНИЕ. Internet Explorer 8 поддерживает событие readystatechange, которое может использоваться для определения готовности DOM.

2 голосов
/ 12 ноября 2011

Вот один из способов - запустить скрипт внизу страницы. Кроме того, используя window.onload, вы можете дождаться загрузки всех изображений / скриптов. Или вы можете просто поместить код внизу, не дожидаясь загрузки изображений.

<html>
<head>
</head>
<body>
</body>
<script language="text/javascript">
  window.onload = (function (oldOnLoad) {
    return function () {
      if (oldOnLoad) { 
        olOnLoad();  //fire old Onload event that was attached if any.
      }
      // your code to run after images/scripts are loaded
    }
  })(window.onload);

  // your code to run after DOM is loaded
</script>
</html>

Отредактировано: для комментария Вилкса

Здесь приведено множество привязок при загрузке http://jsfiddle.net/uTF2N/3/

...