Как проверить, готов ли DOM без фреймворка?

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

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

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

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

7 ответов

Решение

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);
}

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

(function() {
    var state = document.readyState;
    if(state === 'interactive' || state === 'complete') {
        // do stuff
    }
    else setTimeout(arguments.callee, 100);
})();

Браузеры 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();
        }
    }
},

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

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

if ( !!(window.addEventListener) )
  window.addEventListener("DOMContentLoaded", execute)
else // MSIE
  window.attachEvent("onload", execute)

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

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

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

Мы можем просто использоватьDOMContentLoadedэто чистый подход JavaScript.

Вот один из способов - запустить скрипт внизу страницы. Кроме того, используя 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/

Другие вопросы по тегам