Дом Javascript готов?

Я знаю, что могу использовать разные фреймворки, такие как прототип или jQuery, чтобы прикрепить функцию к window.onload, но это не то, что мне нужно.

Мне нужно что-то вроде .readyState, чтобы я мог сделать что-то вроде этого:

if(document.isReady){
  var id = document.getElem ...
}

есть ли другой способ, кроме использования того, что делают фреймворки?


person kristian nissen    schedule 30.07.2009    source источник
comment
Надежное обнаружение DOM-готовности в кросс-браузерном режиме не является тривиальной задачей. Почему вы не хотите использовать один из проверенных фреймворков?   -  person Mauricio Scheffer    schedule 30.07.2009
comment
Я бы порекомендовал взглянуть на domassistant - это очень легкая библиотека. или проверьте d-lite для дополнительного легкого набора функций.   -  person dusoft    schedule 30.07.2009
comment
Меня попросили не делать этого, в принципе.   -  person kristian nissen    schedule 31.07.2009
comment
См. мой ответ на аналогичный вопрос для ссылки в кроссбраузерный объект DOMReady.   -  person Victor    schedule 28.01.2011
comment
Вы можете пересмотреть правильный ответ.   -  person Patrick W. McMahon    schedule 20.09.2014
comment
согласен с @PatrickW.McMahon, правильный ответ должен состоять в том, чтобы с 2017 года использовать стандартный document.addEventListener('DOMContentLoaded' ..., как предлагается ниже (почти скрыто), вместо библиотеки.   -  person Pierre H.    schedule 08.09.2017


Ответы (10)


я обновил код библиотеки DOMAssistant он отлично работает со мной

var domReady = (function (){
  var arrDomReadyCallBacks = [] ;
  function excuteDomReadyCallBacks(){
       for (var i=0; i < arrDomReadyCallBacks.length; i++) {
         arrDomReadyCallBacks[i]();
       }
       arrDomReadyCallBacks = [] ;
  }

  return function (callback){
    arrDomReadyCallBacks.push(callback);
     /* Mozilla, Chrome, Opera */
      if (document.addEventListener ) {
          document.addEventListener('DOMContentLoaded', excuteDomReadyCallBacks, false);
      }
    /* Safari, iCab, Konqueror */
    if (/KHTML|WebKit|iCab/i.test(navigator.userAgent)) {
        browserTypeSet = true ;
        var DOMLoadTimer = setInterval(function () {
            if (/loaded|complete/i.test(document.readyState)) {
                //callback();
                excuteDomReadyCallBacks();
                clearInterval(DOMLoadTimer);
            }
        }, 10);
    }
    /* Other web browsers */

    window.onload = excuteDomReadyCallBacks;
}
})()
person Yehia    schedule 12.08.2013
comment
почему голосование против? код протестирован с т.е. 8, firefox и chrome. - person Yehia; 02.12.2014
comment
Ваш пример — машина Руба Голдберга. Помните при программировании метод KISS. Существуют простые однострочные решения для решения проблемы без необходимости дополнительной обработки. Пожалуйста, добавьте больше документации о том, почему ваше решение необходимо по сравнению с более простыми однострочными решениями. Фрагменты кода без документов не получают много голосов. - person Patrick W. McMahon; 23.01.2015

Редактировать: С приближением 2018 года я думаю, что безопасно слушать DOMContentLoaded.

function fireOnReady() { /* ... */ }
if (document.readyState === 'complete') {
    fireOnReady();
} else {
    document.addEventListener("DOMContentLoaded", fireOnReady);
}

Обратите внимание, что событие срабатывает только один раз при загрузке страницы! Если вам нужно поддерживать действительно старые браузеры, ознакомьтесь с очень легким скриптом, который я собрал ниже.



Только для исторической справки:



jQuery имеет недокументированное свойство isReady, которое используется для внутреннего использования, чтобы определить, сработало ли событие готовности DOM:

if($.isReady) {
    // DOM is ready
} else {
    // DOM is not yet ready
}

Я начал с 1.5.2, вернулся к 1.3.2, и свойство есть. Хотя это недокументировано, я бы сказал, что вы можете положиться на это свойство в будущих версиях jQuery. Редактировать: И год спустя - v1.7.2, они все еще используют $.isReady - все еще недокументированный, поэтому, пожалуйста, используйте на свой страх и риск. Будьте осторожны при обновлении.

Изменить: версия 1.9, они все еще используют $.isReady — все еще недокументированные

Изменить: версия 2.0 со всеми "основными" изменениями по-прежнему использует $.isReady — все еще недокументированная

Редактировать: v3.x по-прежнему использует $.isReady — все еще недокументированный

Редактировать: Как отметили несколько человек, приведенное выше на самом деле не отвечает на вопрос. Поэтому я только что создал мини-фрагмент, готовый к DOM, вдохновленный фрагмент еще меньшего размера, готовый к DOM. Дастин создал изящный способ проверки документа readyState примерно так:

if( !/in/.test(document.readyState) ) {
    // document is ready
} else {
    // document is NOT ready
}

Причина, по которой это работает, заключается в том, что браузер имеет 3 состояния загрузки: «загрузка», «интерактивный» и «завершенный» (старый WebKit также использовал «загружено», но вам больше не нужно об этом беспокоиться) . Вы заметите, что и «загрузка», и «интерактив» содержат текст «in»… поэтому, если строка «in» находится внутри document.readyState, значит, мы еще не готовы.

person Ryan Wheale    schedule 13.06.2011
comment
Не уверен, почему голосование против. Я объяснил, что это недокументировано. Отладка этой проблемы в будущих версиях jQuery будет чрезвычайно простой, и это одна из тех переменных с самоописанием, которые никогда не пройдут лучшее имя для этого теста и поэтому, вероятно, никогда не будут переименованы. что угодно ... Я бы хотел, чтобы люди объяснили отрицательные голоса. - person Ryan Wheale; 02.08.2012
comment
Это не отвечает на вопрос (ОП не хочет использовать фреймворк). Однако он дает хороший ответ на вопрос, помеченный как точная копия этого вопроса (+1 от меня). stackoverflow.com/questions/8373910/ - person Brent Bradburn; 03.02.2013
comment
Upvoted- не отвечает на этот вопрос, но отвечает на вопросы многих людей, попавших сюда. - person bjedrzejewski; 07.10.2013
comment
Требование состояло в том, чтобы подготовить дом без использования фреймворка. Ваш пример решает проблему, но с использованием фреймворка. Это должно быть частью другого вопроса о том, как подготовить dom с помощью JQuery, но не должно быть решением текущего вопроса. Не голосуйте за решение другого вопроса. Голосуйте только за, когда это решает текущий вопрос. - person Patrick W. McMahon; 14.10.2014
comment
@et al - Это был один из моих первых ответов на S.O. и я не был мудр в своих путях. Благодаря тем, кто указал на мою недальновидность, я давно обновил свой ответ, включив в него решение без фреймворка. - person Ryan Wheale; 14.10.2014
comment
Голосую за признание близорукости и ее исправление. - person Mac; 15.12.2014
comment
Спасибо, что исправили свой ответ, чтобы он соответствовал требованиям вопроса. - person Patrick W. McMahon; 23.01.2015

Хотя я обычно выступаю за то, чтобы избегать использования фреймворков без необходимости, я бы сказал, что в этом случае их использование вполне нормально. Вот jQuery:

$(function () {
    // do stuff after DOM has loaded
});

Обратите внимание, что это НЕ то же самое, что событие window.onload, так как onload выполняется первым после загрузки других ресурсов (изображений и т. д.). Код, который я использовал в своем примере, будет выполняться, когда DOM завершит загрузку, т. е. когда вся структура HTML доступен (не обязательно, когда доступны изображения, CSS и т. д.)

Если вам нужна проверяемая переменная, вы можете установить ее в готовой функции:

var documentIsReady = false;
$(function () { documentIsReady = true; });

Конечно, вы можете найти даже более легкие библиотеки, чем jQuery, если все, что вы хотите сделать, это проверить готовность к DOM. Но используйте библиотеку в тех случаях, когда разные браузеры ведут себя по-разному (это один из таких случаев).

Используя некоторый код из библиотеки DOMAssistant, ваша собственная функция «DOM готова» не должна быть слишком сложной:

var domLoaded = function (callback) {
    /* Internet Explorer */
    /*@cc_on
    @if (@_win32 || @_win64)
        document.write('<script id="ieScriptLoad" defer src="//:"><\/script>');
        document.getElementById('ieScriptLoad').onreadystatechange = function() {
            if (this.readyState == 'complete') {
                callback();
            }
        };
    @end @*/
    /* Mozilla, Chrome, Opera */
    if (document.addEventListener) {
        document.addEventListener('DOMContentLoaded', callback, false);
    }
    /* Safari, iCab, Konqueror */
    if (/KHTML|WebKit|iCab/i.test(navigator.userAgent)) {
        var DOMLoadTimer = setInterval(function () {
            if (/loaded|complete/i.test(document.readyState)) {
                callback();
                clearInterval(DOMLoadTimer);
            }
        }, 10);
    }
    /* Other web browsers */
    window.onload = callback;
};

Не проверял, но должно работать. Я упростил его из DOMAssistant, потому что DOMAssistant допускает несколько обратных вызовов и имеет проверку, чтобы убедиться, что вы не можете добавить одну и ту же функцию дважды и т. д.

person Blixt    schedule 30.07.2009
comment
Это единственное, что мне нужно от фреймворка, все остальное, что он должен обслуживать, мне не нужно, поэтому, если возможно, я бы предпочел не использовать фреймворк в этом случае, иначе я бы пошел с jquery - person kristian nissen; 31.07.2009
comment
Хорошо, я добавил упрощенный код из DOMAssistant, можете попробовать. Согласно их сайту, он должен работать во всех основных браузерах. domassistant.com/documentation/DOMAssistantLoad-module.php - person Blixt; 31.07.2009
comment
Мой код будет вызывать callback до двух раз (поскольку window.onload должен выполняться во всех браузерах). При обработке события проверяйте, было ли уже вызвано callback, и возвращайтесь, если это так (это то, что делает DOMAssistant, но я удалил эту часть). - person Blixt; 31.07.2009
comment
изменение значения window.onload без учета фактического значения может привести к неожиданному поведению в коде других скриптов. Также мы не можем вызывать domLoaded дважды, так как будет использован только последний. - person fguillen; 07.10.2011
comment
Этот код работал для меня! За исключением того, что мне пришлось использовать else if, иначе firefox сработает дважды. - person jisaacstone; 30.11.2011
comment
if (/loaded|complete/i.test(document.readyState)) { callback(); return; } должен быть вверху функции, если страница уже загружена. - person enyo; 26.08.2012
comment
Это, в отличие от domready jQuery, не добавит обратных вызовов! По крайней мере, для window.onload он заменит существующие обратные вызовы только новыми! - person Kzqai; 25.10.2012
comment
+1 за то, что не сказал just use jquery or x library Я ненавижу, когда люди так делают. - person Vitim.us; 06.05.2013
comment
DOMContentLoaded срабатывает один раз, когда DOM полностью загружен и проанализирован. все дополнительные вещи, которые вы делаете, не нужны. - person Patrick W. McMahon; 14.10.2014

За 5 лет, прошедших с тех пор, как был задан этот вопрос, DOMContentLoaded стал повсеместно поддерживаемым событием, и вы можете просто использовать его.

document.addEventListener('DOMContentLoaded', function() {
    //.. do stuff ..
}, false);
person Damon Smith    schedule 04.02.2015
comment
Я как раз собирался сделать комментарий о DOMContentLoaded. Поскольку здесь нет особых мнений, я предполагаю, что это правильный путь? - person Nocturno; 27.08.2015
comment
Это поддерживается в каждом современном браузере caniuse.com/#search=DOMContentLoaded. - person str; 31.10.2015
comment
Почему вы опубликовали это через год после того, как люди уже прокомментировали addEventListener(). Вы не добавили ничего, что уже сделали другие ответы до вашего. - person Patrick W. McMahon; 19.10.2016
comment
Что ж, извини, Патрик, я знаю, кажется, что я намеренно повторно ответил на этот вопрос так же, как и ты, чтобы украсть твои интернет-баллы, но я, честно говоря, не видел твоего ответа. В то время я пролистал и подумал, что это забавно, никто не указал, что это больше не проблема, требующая стороннего кода. Я думаю, что это все еще часть моего ответа, за которую люди голосуют, что теперь это повсеместно поддерживается. - person Damon Smith; 23.10.2016

Посмотрите эту демонстрацию от Microsoft. -> http://ie.microsoft.com/testdrive/HTML5/DOMContentLoaded/Default.html А вот и суть кода, позволяющего запускать JS на готовом DOM...

(function () {
    function load2(){
        // put whatever you need to load on DOM ready in here
        document.getElementById("but3").addEventListener("click", doMore, false);
    }
    if (window.addEventListener) {
        window.addEventListener('DOMContentLoaded', load2, false);
    } else {
        window.attachEvent('onload', load2);
    }
} ());

Вот некоторые исходники javascript для демонстрации. http://ie.microsoft.com/testdrive/Includes/Script/ReturnAndShareControls.js

Это работает хорошо. Отлично!!.. в Google Chrome и IE 9.

person Randy Skretka    schedule 30.10.2011
comment
Я считаю, что это должно быть document.addEventListener(..., а не window - person banderson623; 08.01.2014
comment
@ banderson623 Извините, но я слишком долго не использовал код в своем посте, чтобы вспомнить его достаточно хорошо. Возможно, обновления браузера внесли изменения, которые вы предлагаете. - person Randy Skretka; 10.01.2014
comment
вам не нужно значение false в конце addEventListener('DOMContentLoaded', load2, false) DOMContentLoaded не имеет родительского элемента для прохождения. - person Patrick W. McMahon; 30.09.2014

document.addEventListener("DOMContentLoaded", function(e){
    console.log("dom ready");//output to web browser console
});

для этого не требуется JQuery. Нет необходимости передавать третий параметр в DOMContentLoaded, так как у этого события нет родителя для прохождения события. Также не нужно увлекаться тем, что говорят все остальные. Это сообщит вам, когда DOM будет полностью загружен и готов к использованию. Я LOLed, когда я заметил библиотеку помощника DOM. Эта библиотека абсолютно бесполезна.

Событие DOMContentLoaded запускается, когда документ полностью загружен и проанализирован, не дожидаясь завершения загрузки таблиц стилей, изображений и подкадров.

addEventListener() — отличная функция для проверки любого события, включая статус готовности DOM. При использовании «DOMContentLoaded» третий параметр в addEventListener() не нужен, так как у этого триггера нет родительского элемента для передачи события. В моем примере выше вы заметите, что второй параметр является анонимной функцией. Вы также можете передать имя функции во второй параметр.

document.addEventListener([(string)event trigger], [function],[(boolean)traverse DOM tree]);

Еще одно преимущество использования этого над JQuery заключается в том, что он не сломается при обновлении JQuery.

person Patrick W. McMahon    schedule 29.08.2014

jQuery не использует window.onload.

$(document).ready() ждет, пока DOM загрузится и его можно будет пройти (остальное содержимое может быть загружено или не загружено к этому моменту).

Если вы откроете исходный код для jQuery и разберетесь в беспорядке, вы обнаружите, что работа выполняется методом bindReady(), который имеет несколько разных реализаций для разных браузеров, и только когда все эти реализации терпят неудачу, он возвращается к прослушиванию для событие загрузки для окна.

person Justin Niessner    schedule 30.07.2009
comment
@PatrickW.McMahon - я не предлагал использовать jQuery в своем ответе. Если вы прочитаете это ближе, я сказал ОП прочитать исходный код jQuery, чтобы увидеть, как они выполняют свое готовое обнаружение, чтобы он мог его имитировать. - person Justin Niessner; 01.10.2014
comment
Зачем просить кого-то копаться в коде jQuery для чего-то, если вы можете связать их с документацией w3schools для получения состояния DOM? Это занимает меньше времени и не нужно копаться в тысячах строк JQuery и следить за флагами и триггерами JQuery только для того, чтобы узнать, что они обернули демонстрацию w3school в функцию JQuery. Простое решение обычно является лучшим решением. Время программиста ценно. Выберите наиболее эффективное решение. К тому времени, когда он углубился во фреймворк JQuery, он уже мог просто использовать JQuery. - person Patrick W. McMahon; 14.10.2014
comment
@PatrickW.McMahon - не нужно смотреть на тысячи строк. В своем ответе я сказал ОП, на какой именно метод смотреть. W3Schools не собирается показывать OP лучший способ реализации идентичных функций в каждом браузере. Если вы хотите стать лучшим разработчиком, вы учитесь на хорошем коде. У W3Schools определенно нет хорошего кода. - person Justin Niessner; 14.10.2014
comment
@Justin Niessner - W3School является руководящим органом в Интернете. Если вы думаете, что они не предоставляют код хорошего качества в соответствии со стандартами, которые они разработали, то у нас большие проблемы. Члены, которые управляют W3School, — это те же люди, которые работают над новыми стандартами HTML5. - person Patrick W. McMahon; 23.01.2015
comment
@PatrickW.McMahon - W3School, безусловно, НЕ является руководящим органом сети. Это может быть W3C (Консорциум World Wide Web) w3.org Школы W3 стали лучше, чем были, но есть еще вопросы. Посетите w3fools.com для получения дополнительной информации. - person Justin Niessner; 23.01.2015
comment
Многие люди, работающие в W3School, являются членами W3C. Я не говорю, что все члены W3C работают в W3School, но многие сотрудники W3School являются членами W3C. Поэтому у них часто есть информация, опубликованная W3C. Мне не удалось найти их в списке w3.org/Consortium/Member/List но я полагаю, что они находятся под корпоративным именем. Не по названию сайтов. - person Patrick W. McMahon; 23.01.2015
comment
@PatrickW.McMahon - W3Schools была создана и до сих пор принадлежит Refsnes Data. Они не являются членами W3C. Кроме того, публично заявлено, что W3Schools никоим образом не связаны с W3C. Если у вас есть список членов W3C, нанятых Refsnes Data, я был бы очень признателен за его просмотр. - person Justin Niessner; 23.01.2015

На самом деле это одна из основных причин, по которой большинство людей используют такие фреймворки, как jQuery, потому что решение этой проблемы несовместимо в разных браузерах.

person Scott Fox    schedule 30.07.2009
comment
Я знаю, и я сам активный пользователь jquery, но в этом случае я не хочу полагаться на фреймворк, меня просили избегать этого. - person kristian nissen; 31.07.2009
comment
Я бы предложил, возможно, посмотреть исходный код на jQuery и перенести только код, который вы хотите, в свой проект. - person Scott Fox; 31.07.2009
comment
подготовка DOM - это одна строка document.addEventListener("DOMContentLoaded", function(e){/*dom ready do something*/}); почему это так сложно, что вам нужно использовать фреймворк, чтобы подготовить dom? - person Patrick W. McMahon; 14.10.2014

Попробуйте следующее:
Ссылка: onDomReady на GitHub или источник ниже:

if(document.ondomready == undefined) {
    document.ondomready = {};
    document.ondomready = null;
} else {
    document.ondomready=document.ondomready;
}
var oldonload=document.onload;
var isLaunched = 0;
document.onload = function() {  
    if(oldonload !== null) {
        oldonload.call();
    }
};
document.addEventListener("DOMContentLoaded", function onDom(evt) {
    var olddomready = document.ondomready;
    if(olddomready !== null) {
        if(isLaunched == 0) {
            olddomready.call(evt);
            isLaunched == 1;
            //We now launched the mapped DOMContentLoaded Event
        } else {
            //We already launched DOMContentLoaded Event
        }
    }
}, false);

Я уже тестировал это в Opera 11.x/12.x. На других еще не проверял. Дайте мне знать, если они это сделают.

Примечание. Я еще не загрузил репозиторий, но скоро сделаю это в свободное время.

person dsrdakota    schedule 29.06.2012
comment
DOMContentLoaded срабатывает один раз, когда DOM полностью загружен и проанализирован. все дополнительные вещи, которые вы добавили, ничего не делают. - person Patrick W. McMahon; 14.10.2014

Если вам нужны библиотеки меньшего размера, которые делают только определенные вещи, вы можете использовать библиотеки в microjs. Для рассматриваемого вопроса можно использовать готовый метод DOMStatic libs.

person Jerome Anthony    schedule 01.12.2014