$ (документ). уже эквивалентно без jQuery

2017

У меня есть скрипт, который использует $(document).ready , но он не использует ничего другого из jQuery. Я хотел бы облегчить это, удалив зависимость JQuery.

Как я могу реализовать свой собственный $(document).readyфункционал без использования jQuery? Я знаю, что использование window.onloadне будет таким же, как window.onloadпожары после того , как все изображения, кадры и т. Д. Были загружены.

FlySwat
источник
296
... а также определенно не та же функциональность.
Джоэл Мюллер
40
Как говорится в этом ответе , если все, что вам нужно от jQuery, - это то $(document).ready, что вы можете легко решить эту проблему, запустив код в самом низу страницы, а не вверху. HTML5Boilerplate использует именно этот подход.
Blazemonger
3
Почему бы просто не использовать DOMContentLoaded? Это IE9 + caniuse.com/domcontentloaded developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded
Брок,
Я сделал свой звонок в конце документа, и это решило мою проблему. Когда функция вызывается, все загружается.
IgniteCoders
Стоит посмотреть: developer.mozilla.org/en-US/docs/Web/API/Document/readyState
Эндрю

Ответы:

1440

Существует стандартная замена, DOMContentLoadedкоторая поддерживается более чем 98% браузеров , но не IE8:

document.addEventListener("DOMContentLoaded", function(event) { 
  //do work
});

Нативная функция jQuery намного сложнее, чем просто window.onload, как показано ниже.

function bindReady(){
    if ( readyBound ) return;
    readyBound = true;

    // Mozilla, Opera and webkit nightlies currently support this event
    if ( document.addEventListener ) {
        // Use the handy event callback
        document.addEventListener( "DOMContentLoaded", function(){
            document.removeEventListener( "DOMContentLoaded", arguments.callee, false );
            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", function(){
            if ( document.readyState === "complete" ) {
                document.detachEvent( "onreadystatechange", arguments.callee );
                jQuery.ready();
            }
        });

        // If IE and not an iframe
        // continually check to see if the document is ready
        if ( document.documentElement.doScroll && window == window.top ) (function(){
            if ( jQuery.isReady ) return;

            try {
                // If IE is used, use the trick by Diego Perini
                // http://javascript.nwbox.com/IEContentLoaded/
                document.documentElement.doScroll("left");
            } catch( error ) {
                setTimeout( arguments.callee, 0 );
                return;
            }

            // and execute any waiting functions
            jQuery.ready();
        })();
    }

    // A fallback to window.onload, that will always work
    jQuery.event.add( window, "load", jQuery.ready );
}
Чад Грант
источник
19
Реально работающая простая реализация javascript здесь, если кому-то нужен код, который он может просто
вставить
4
Готовый код jQuery DOM выглядит упрощенно: github.com/jquery/jquery/blob/master/src/core/ready.js
Хосе Нобиле
2
@JoseNobile, потому что они отказались от поддержки старых браузеров
huysentruitw
16
Я думаю, что мы все готовы перейти от IE8 ...;). Спасибо за ссылку, @JoseNobile.
Кон Антонакос
13
DOMContentLoaded не будет работать, если скрипт загружается впоследствии. Готовый документ JQuery выполняется всегда.
Джаред Инсел
343

Редактировать:

Вот жизнеспособная замена для JQuery готов

function ready(callback){
    // in case the document is already rendered
    if (document.readyState!='loading') callback();
    // modern browsers
    else if (document.addEventListener) document.addEventListener('DOMContentLoaded', callback);
    // IE <= 8
    else document.attachEvent('onreadystatechange', function(){
        if (document.readyState=='complete') callback();
    });
}

ready(function(){
    // do something
});

Взято из https://plainjs.com/javascript/events/running-code-when-the-document-is-ready-15/

Еще одна хорошая функция domReady, взятая из https://stackoverflow.com/a/9899701/175071


Поскольку принятый ответ был очень далек от завершения, я соединил «готовую» функцию, например jQuery.ready() основанную на исходном коде jQuery 1.6.2:

var ready = (function(){

    var readyList,
        DOMContentLoaded,
        class2type = {};
        class2type["[object Boolean]"] = "boolean";
        class2type["[object Number]"] = "number";
        class2type["[object String]"] = "string";
        class2type["[object Function]"] = "function";
        class2type["[object Array]"] = "array";
        class2type["[object Date]"] = "date";
        class2type["[object RegExp]"] = "regexp";
        class2type["[object Object]"] = "object";

    var ReadyObj = {
        // Is the DOM ready to be used? Set to true once it occurs.
        isReady: false,
        // A counter to track how many items to wait for before
        // the ready event fires. See #6781
        readyWait: 1,
        // Hold (or release) the ready event
        holdReady: function( hold ) {
            if ( hold ) {
                ReadyObj.readyWait++;
            } else {
                ReadyObj.ready( true );
            }
        },
        // Handle when the DOM is ready
        ready: function( wait ) {
            // Either a released hold or an DOMready/load event and not yet ready
            if ( (wait === true && !--ReadyObj.readyWait) || (wait !== true && !ReadyObj.isReady) ) {
                // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
                if ( !document.body ) {
                    return setTimeout( ReadyObj.ready, 1 );
                }

                // Remember that the DOM is ready
                ReadyObj.isReady = true;
                // If a normal DOM Ready event fired, decrement, and wait if need be
                if ( wait !== true && --ReadyObj.readyWait > 0 ) {
                    return;
                }
                // If there are functions bound, to execute
                readyList.resolveWith( document, [ ReadyObj ] );

                // Trigger any bound ready events
                //if ( ReadyObj.fn.trigger ) {
                //    ReadyObj( document ).trigger( "ready" ).unbind( "ready" );
                //}
            }
        },
        bindReady: function() {
            if ( readyList ) {
                return;
            }
            readyList = ReadyObj._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( ReadyObj.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", ReadyObj.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", ReadyObj.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();
                }
            }
        },
        _Deferred: function() {
            var // callbacks list
                callbacks = [],
                // stored [ context , args ]
                fired,
                // to avoid firing when already doing so
                firing,
                // flag to know if the deferred has been cancelled
                cancelled,
                // the deferred itself
                deferred  = {

                    // done( f1, f2, ...)
                    done: function() {
                        if ( !cancelled ) {
                            var args = arguments,
                                i,
                                length,
                                elem,
                                type,
                                _fired;
                            if ( fired ) {
                                _fired = fired;
                                fired = 0;
                            }
                            for ( i = 0, length = args.length; i < length; i++ ) {
                                elem = args[ i ];
                                type = ReadyObj.type( elem );
                                if ( type === "array" ) {
                                    deferred.done.apply( deferred, elem );
                                } else if ( type === "function" ) {
                                    callbacks.push( elem );
                                }
                            }
                            if ( _fired ) {
                                deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] );
                            }
                        }
                        return this;
                    },

                    // resolve with given context and args
                    resolveWith: function( context, args ) {
                        if ( !cancelled && !fired && !firing ) {
                            // make sure args are available (#8421)
                            args = args || [];
                            firing = 1;
                            try {
                                while( callbacks[ 0 ] ) {
                                    callbacks.shift().apply( context, args );//shifts a callback, and applies it to document
                                }
                            }
                            finally {
                                fired = [ context, args ];
                                firing = 0;
                            }
                        }
                        return this;
                    },

                    // resolve with this as context and given arguments
                    resolve: function() {
                        deferred.resolveWith( this, arguments );
                        return this;
                    },

                    // Has this deferred been resolved?
                    isResolved: function() {
                        return !!( firing || fired );
                    },

                    // Cancel
                    cancel: function() {
                        cancelled = 1;
                        callbacks = [];
                        return this;
                    }
                };

            return deferred;
        },
        type: function( obj ) {
            return obj == null ?
                String( obj ) :
                class2type[ Object.prototype.toString.call(obj) ] || "object";
        }
    }
    // The DOM ready check for Internet Explorer
    function doScrollCheck() {
        if ( ReadyObj.isReady ) {
            return;
        }

        try {
            // If IE is used, use the trick by Diego Perini
            // http://javascript.nwbox.com/IEContentLoaded/
            document.documentElement.doScroll("left");
        } catch(e) {
            setTimeout( doScrollCheck, 1 );
            return;
        }

        // and execute any waiting functions
        ReadyObj.ready();
    }
    // Cleanup functions for the document ready method
    if ( document.addEventListener ) {
        DOMContentLoaded = function() {
            document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
            ReadyObj.ready();
        };

    } else if ( document.attachEvent ) {
        DOMContentLoaded = function() {
            // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
            if ( document.readyState === "complete" ) {
                document.detachEvent( "onreadystatechange", DOMContentLoaded );
                ReadyObj.ready();
            }
        };
    }
    function ready( fn ) {
        // Attach the listeners
        ReadyObj.bindReady();

        var type = ReadyObj.type( fn );

        // Add the callback
        readyList.done( fn );//readyList is result of _Deferred()
    }
    return ready;
})();

Как пользоваться:

<script>
    ready(function(){
        alert('It works!');
    });
    ready(function(){
        alert('Also works!');
    });
</script>

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

PS: предлагаю компилировать .

Или вы можете использовать http://dustindiaz.com/smallest-domready-ever :

function r(f){/in/.test(document.readyState)?setTimeout(r,9,f):f()}
r(function(){/*code to run*/});

или встроенная функция, если вам нужно только поддерживать новые браузеры (в отличие от готового jQuery, он не запустится, если вы добавите его после загрузки страницы)

document.addEventListener('DOMContentLoaded',function(){/*fun code to run*/})
Тимо Хуовинен
источник
14
@TimoHuovinen Альтернативы: Zepto.js (9,1 кб), Snack.js (8,1 кб), $ dom (2,3 кб) и 140 Medley (0,5 кб). Изменить: Вы также можете взглянуть на Эндер.
Фредерик Краутвальд
2
@FrederikKrautwald $ dom звучит как то, что я хотел бы, но не уверен, отвечает ли это требованиям. Zepto также выглядит многообещающе, спасибо, что поделились!
Тимо Хуовинен
@TimoHuovinen Если вы еще не смотрели на Ender, вам обязательно стоит взглянуть на enderjs.com .
Фредерик Краутвальд
2
@ Тимо Хуовинен: Ваш вопрос очень, очень широкий! Когда был создан jQuery, в нем было много кросс-браузерных проблем, порожденных браузерами, которые сегодня менее значительны. Сегодня «только JavaScript» проще, чем было. В то время создание «большого сжатого 20 КБ, содержащего все», безусловно, было хорошей идеей по многим причинам, поэтому я предпочитаю не перечислять их все.
dotpush
1
Мне это не нравится Если люди предпочитают этот ответ, спросите себя, почему вы хотите отказаться от jQuery. Это немного бессмысленно, если вы просто собираетесь извлекать ту же самую функциональность со всеми этими резервными копиями браузера обратно в ваш пакет. Не в этом ли смысл избегать jQuery?
Фил,
208

Три варианта:

  1. Если scriptэто последний тег тела, DOM будет готов до выполнения тега скрипта
  2. Когда DOM будет готов, «readyState» изменится на «complete»
  3. Поместите все в обработчик событий «DOMContentLoaded»

onreadystatechange

  document.onreadystatechange = function () {
     if (document.readyState == "complete") {
     // document is ready. Do your stuff here
   }
 }

Источник: MDN

DOMContentLoaded

document.addEventListener('DOMContentLoaded', function() {
   console.log('document is ready. I can sleep now');
});

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

Джанкар Махбуб
источник
3
Этот второй пример гораздо более элегантен и лаконичен, чем отмеченные ответы. Почему этот не был отмечен как правильный?
0112
2
Еще +1 для вещи DOMContentLoaded, она сделала именно то, что я хотел.
tripleee
1
onreadystatechange помог мне ... нужно было запустить какой-нибудь скрипт после асинхронной загрузки jquery.
Абрам
2
Так же, как и к вашему сведению, # 1 не совсем верно. Сценарий в конце страницы вполне может быть загружен до того, как DOM будет готов. Вот почему слушатели выше. Они слушают, когда браузер готов. Если положить его в конец, это значит, что загрузка скрипта была медленнее, чем может сделать браузер.
Machavity
1
этот вариант также будет работать, когда документ уже будет загружен, обновите свой (imo best) ответ, если сможете: if (document.readyState == 'complete') {init (); } else {document.onreadystatechange = function () {if (document.readyState == 'complete') {init (); }}}
ZPiDER
87

Разместите свое <script>/*JavaScript code*/</script>право перед закрывающим </body> тегом.

Следует признать, что это может не подходить для всех, так как требует изменения файла HTML, а не просто что-то делать в файле JavaScript document.ready, но все же ...

грабить
источник
Мне кажется, что были проблемы с совместимостью, например, поскольку страница еще не готова, вы не можете делать то или это в этих и тех браузерах. К сожалению, я не могу вспомнить более ясно. Тем не менее +1 за путь, который достаточно близок в 99% всех случаев (и предложенный Yahoo!).
Болдевин
7
На самом деле, размещение элемента script внизу страницы - почти идеальное решение. Он работает в кросс-браузерном режиме и имитирует документ. Единственным недостатком является то, что это (немного) более навязчиво, чем использование какого-либо умного кода, вам придется попросить пользователя создаваемого сценария добавить дополнительный фрагмент сценария для вызова функции ready или init.
Стейн де Витт
@StijndeWitt - Что вы имеете в виду, когда вызываете функцию инициализации? Скрипт, который использует document.ready, не нуждается в другом клиентском коде для его вызова, он самодостаточен и эквивалентен тому, где код включен в конец тела, также может быть автономным и не потребовать другой код, чтобы вызвать его либо.
nnnnnn
1
Почему бы не поставить скрипт после закрывающего тега body и до закрывающего </html>тега?
Чарльз Холброу
1
@CharlesHolbrow Хотя все браузеры интерпретируют его правильно, если вы хотите, чтобы он был действительным html, htmlтег должен содержать только headи body.
Альваро Монторо
66

Бедное мужское решение:

var checkLoad = function() {   
    document.readyState !== "complete" ? setTimeout(checkLoad, 11) : alert("loaded!");   
};  

checkLoad();  

Посмотреть скрипку

Добавил этот, немного лучше, я думаю, собственный объем и не рекурсивный

(function(){
    var tId = setInterval(function() {
        if (document.readyState == "complete") onComplete()
    }, 11);
    function onComplete(){
        clearInterval(tId);    
        alert("loaded!");    
    };
})()

Посмотреть скрипку

Якоб Штернберг
источник
8
@PhilipLangford Или просто поместите его в a setIntervalи полностью удалите рекурсию.
Алекс W
1
@ Raveren, хм, ты прав, я уверен, что проверил это, когда опубликовал. В любом случае, это стало еще проще, теперь функция вызывается без переноса.
Якоб Штернберг
24
Это не сексуально. Нет простите. Использование таймеров / интервалов для обнаружения чего-либо может «работать», но если вы продолжите программировать, как этот, любой более крупный проект, достойный его соли, начнет нырять. Не взламывайте такие вещи вместе, как это. Сделай это правильно. Пожалуйста. Этот вид кода вредит экосистеме разработки, потому что есть лучшее решение, и вы ЗНАЕТЕ его.
dudewad
1
Я думаю, что этот ответ намного ближе к dustindiaz.com/smallest-domready-ever, поэтому я улучшил скрипт: jsfiddle.net/iegik/PT7x9
iegik
1
@ReidBlomquist Да, и это «неправильный» путь, и это то, на что я указываю (хотя и немного категорично, я знаю). Вы могли бы сказать, что, делая это неправильно, это как-то «помогает» экосистеме, но проблема в том, что с количеством плохого кода, который люди принимают за «хороший» код, потому что у них нет опыта, чтобы узнать что-то лучше НЕ помогает экосистеме, потому что тогда они возьмут этот плохой код и воплотят его в реальное производственное архитектурное решение. Так что, я думаю, нам просто придется расходиться во мнениях по поводу этой «ошибки».
dudewad
34

Я использую это:

document.addEventListener("DOMContentLoaded", function(event) { 
    //Do work
});

Примечание. Возможно, это работает только в новых браузерах, особенно в следующих: http://caniuse.com/#feat=domcontentloaded

Дастин Дэвис
источник
13
IE9 и выше на самом деле
Паскалиус
Это также прекрасно работает в скриптах содержимого Chrome Extension, если вы перехватываете событие document_start или document_idle.
Воломике
21

Действительно, если вы заботитесь только о Internet Explorer 9+ , этого кода будет достаточно для замены jQuery.ready:

    document.addEventListener("DOMContentLoaded", callback);

Если вы беспокоитесь об Internet Explorer 6 и некоторых действительно странных и редких браузерах, это будет работать:

domReady: function (callback) {
    // Mozilla, Opera and WebKit
    if (document.addEventListener) {
        document.addEventListener("DOMContentLoaded", callback, false);
        // If Internet Explorer, the event model is used
    } else if (document.attachEvent) {
        document.attachEvent("onreadystatechange", function() {
            if (document.readyState === "complete" ) {
                callback();
            }
        });
        // A fallback to window.onload, that will always work
    } else {
        var oldOnload = window.onload;
        window.onload = function () {
            oldOnload && oldOnload();
            callback();
        }
    }
},
Дэн
источник
18

Этот вопрос был задан довольно давно. Для тех, кто только видит этот вопрос, теперь есть сайт под названием «вам может не понадобиться jquery» который разбит - по уровню необходимой поддержки IE - все функции jquery и предоставляют некоторые альтернативные, более мелкие библиотеки.

Скрипт, готовый к использованию в IE8, может не потребовать jquery

function ready(fn) {
    if (document.readyState != 'loading')
        fn();
    else if (document.addEventListener)
        document.addEventListener('DOMContentLoaded', fn);
    else
        document.attachEvent('onreadystatechange', function() {
            if (document.readyState != 'loading')
                fn();
        });
}
chugadie
источник
Интересно, почему 'onreadystatechange'это нужно, а неdocument.attachEvent('onload', fn);
Люк
13

Я недавно использовал это для мобильного сайта. Это упрощенная версия Джона Ресига из «Техники Pro JavaScript». Это зависит от addEvent.

var ready = ( function () {
  function ready( f ) {
    if( ready.done ) return f();

    if( ready.timer ) {
      ready.ready.push(f);
    } else {
      addEvent( window, "load", isDOMReady );
      ready.ready = [ f ];
      ready.timer = setInterval(isDOMReady, 13);
    }
  };

  function isDOMReady() {
    if( ready.done ) return false;

    if( document && document.getElementsByTagName && document.getElementById && document.body ) {
      clearInterval( ready.timer );
      ready.timer = null;
      for( var i = 0; i < ready.ready.length; i++ ) {
        ready.ready[i]();
      }
      ready.ready = null;
      ready.done = true;
    }
  }

  return ready;
})();
Джеймс
источник
13
Будьте осторожны с этим кодом. Это НЕ эквивалентно $ (документ) .ready. Этот код запускает обратный вызов, когда document.body готов, что не гарантирует полной загрузки DOM.
Каролис
12

Кросс-браузер (тоже старые браузеры) и простое решение:

var docLoaded = setInterval(function () {
    if(document.readyState !== "complete") return;
    clearInterval(docLoaded);

    /*
        Your code goes here i.e. init()
    */
}, 30);

Отображение оповещения в jsfiddle

Pawel
источник
За исключением случаев, когда загрузка DOM занимает более 30 мс, ваш код не будет выполняться.
Quelklef
1
@Quelklef это setInterval, а не setTimeout
Pawel
11

Ответ jQuery был довольно полезен для меня. С небольшим заводом это соответствовало моим потребностям хорошо. Надеюсь, это кому-нибудь еще поможет.

function onReady ( callback ){
    var addListener = document.addEventListener || document.attachEvent,
        removeListener =  document.removeEventListener || document.detachEvent
        eventName = document.addEventListener ? "DOMContentLoaded" : "onreadystatechange"

    addListener.call(document, eventName, function(){
        removeListener( eventName, arguments.callee, false )
        callback()
    }, false )
}
Miere
источник
в некоторых браузерах removeListenerнеобходимо вызывать документ с контекстом, т.е. removeListener.call(document, ...
Рон
9

Вот самый маленький фрагмент кода для проверки готовности DOM, который работает во всех браузерах (даже в IE 8):

r(function(){
    alert('DOM Ready!');
});
function r(f){/in/.test(document.readyState)?setTimeout('r('+f+')',9):f()}

Смотрите этот ответ .

Антара Рой
источник
6

Просто добавьте это внизу вашей HTML-страницы ...

<script>
    Your_Function();
</script>

Потому что документы HTML анализируются сверху вниз.

davefrassoni
источник
7
Откуда вы знаете, что DOM создается при выполнении этого кода? В том числе загруженный и проанализированный CSS? API браузера DOMContentLoaded предназначен для этого.
Дан
Это действительно зависит от того, что он хочет сделать с JS. Если он действительно должен выполнить что-то, когда страница закончилась или нет.
davefrassoni
5

Стоит поискать в Rock Solid addEvent () и http://www.braksator.com/how-to-make-your-own-jquery .

Вот код на случай, если сайт не работает

function addEvent(obj, type, fn) {
    if (obj.addEventListener) {
        obj.addEventListener(type, fn, false);
        EventCache.add(obj, type, fn);
    }
    else if (obj.attachEvent) {
        obj["e"+type+fn] = fn;
        obj[type+fn] = function() { obj["e"+type+fn]( window.event ); }
        obj.attachEvent( "on"+type, obj[type+fn] );
        EventCache.add(obj, type, fn);
    }
    else {
        obj["on"+type] = obj["e"+type+fn];
    }
}

var EventCache = function(){
    var listEvents = [];
    return {
        listEvents : listEvents,
        add : function(node, sEventName, fHandler){
            listEvents.push(arguments);
        },
        flush : function(){
            var i, item;
            for(i = listEvents.length - 1; i >= 0; i = i - 1){
                item = listEvents[i];
                if(item[0].removeEventListener){
                    item[0].removeEventListener(item[1], item[2], item[3]);
                };
                if(item[1].substring(0, 2) != "on"){
                    item[1] = "on" + item[1];
                };
                if(item[0].detachEvent){
                    item[0].detachEvent(item[1], item[2]);
                };
                item[0][item[1]] = null;
            };
        }
    };
}();

// Usage
addEvent(window, 'unload', EventCache.flush);
addEvent(window, 'load', function(){alert("I'm ready");});
Бен
источник
Вторая ссылка не работает.
Питер Мортенсен
4

Этот кросс-браузерный код вызовет функцию, когда DOM будет готов:

var domReady=function(func){
    var scriptText='('+func+')();';
    var scriptElement=document.createElement('script');
    scriptElement.innerText=scriptText;
    document.body.appendChild(scriptElement);
};

Вот как это работает:

  1. Первая строка domReadyвызывает toStringметод функции, чтобы получить строковое представление передаваемой функции и обернуть его в выражение, которое немедленно вызывает функцию.
  2. Остальная часть domReadyсоздает элемент сценария с выражением и добавляет его к bodyдокументу.
  3. Браузер запускает теги сценариев, добавленные bodyпосле того, как DOM готов.

Например, если вы сделаете это:, domReady(function(){alert();});к bodyэлементу будет добавлено следующее :

 <script>(function (){alert();})();</script>

Обратите внимание, что это работает только для пользовательских функций. Следующее не будет работать:domReady(alert);

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

Это 2020 год и <script>тег имеет deferатрибут.

например:

<script src="demo_defer.js" defer></script>

это указывает, что скрипт выполняется, когда страница закончила анализ.

https://www.w3schools.com/tags/att_script_defer.asp

Миксер
источник
3

Как насчет этого решения?

// other onload attached earlier
window.onload=function() {
   alert('test');
};

tmpPreviousFunction=window.onload ? window.onload : null;

// our onload function
window.onload=function() {
   alert('another message');

   // execute previous one
   if (tmpPreviousFunction) tmpPreviousFunction();
};
Майк
источник
3
Вы можете использовать addEventListener для окна с «load». Слушатели выполняются один за другим и не нуждаются в цепочке вручную.
Zaffy
1
Но нагрузка отличается от готовой. «Загрузка» происходит даже до того, как документ «готов». В готовом документе загружен DOM, в загруженном окне необязательно готов DOM. Хороший ответ, хотя
Mzn
1
@Mzn: я думаю, что это задом наперед. Я думаю, что документ готово происходит до события загрузки окна. «В общем, нет необходимости ждать полной загрузки всех изображений. Если код может быть выполнен раньше, обычно лучше поместить его в обработчик, отправленный методу .ready ()». ( api.jquery.com/load-event )
Тайлер Рик
это переопределит остальные события window.onload на странице и вызовет проблемы. это должно добавить событие поверх существующего.
Теоман Шипахи
Событие загрузки может произойти слишком поздно. Больно использовать его, когда зависит от внешних сторонних js / изображений ... Не отвечающий сервер, который вы не контролируете, и все терпит неудачу. Использование DOMContentLoaded - это не просто оптимизация, это еще и безопаснее!
dotpush
3

Всегда полезно использовать эквиваленты JavaScript по сравнению с jQuery. Одна из причин заключается в том, что от библиотеки зависит меньше библиотек, и они работают намного быстрее, чем эквиваленты jQuery.

Одна из фантастических ссылок на jQuery-эквиваленты - http://youmightnotneedjquery.com/ .

Что касается вашего вопроса, я взял приведенный ниже код по вышеуказанной ссылке :) Единственное предостережение: он работает только с Internet Explorer 9 и более поздними версиями.

function ready(fn) {
    if (document.readyState != 'loading') {
        fn();
    }
    else {
        document.addEventListener('DOMContentLoaded', fn);
    }
}
Vatsal
источник
3

Самый минимальный и 100% рабочий

Я выбрал ответ от PlainJS, и он отлично работает для меня. Он распространяется DOMContentLoadedтак, что он может быть принят во всех браузерах.


Эта функция является эквивалентом метода jQuery $(document).ready():

document.addEventListener('DOMContentLoaded', function(){
    // do something
});

Однако, в отличие от jQuery, этот код будет корректно работать только в современных браузерах (IE> 8), и не будет, если документ уже отрисован во время вставки этого скрипта (например, через Ajax). Поэтому нам нужно немного расширить это:

function run() {
    // do something
}

// in case the document is already rendered
if (document.readyState!='loading') run();
// modern browsers
else if (document.addEventListener) 
document.addEventListener('DOMContentLoaded', run);
// IE <= 8
else document.attachEvent('onreadystatechange', function(){
    if (document.readyState=='complete') run();
});

Это охватывает практически все возможности и является жизнеспособной заменой помощнику jQuery.

Шивам Шарма
источник
2

Мы нашли быструю кросс-браузерную реализацию, которая может помочь в большинстве простых случаев с минимальной реализацией:

window.onReady = function onReady(fn){
    document.body ? fn() : setTimeout(function(){ onReady(fn);},50);
};
Малко
источник
что doc.body?!
Наби КАЗ
2

Представленные здесь решения setTimeout / setInterval будут работать только при определенных обстоятельствах.

Проблема проявляется особенно в старых версиях Internet Explorer до 8.

Переменные, влияющие на успех этих решений setTimeout / setInterval:

1) dynamic or static HTML
2) cached or non cached requests
3) size of the complete HTML document
4) chunked or non chunked transfer encoding

оригинальный (нативный Javascript) код для решения этой конкретной проблемы находится здесь:

https://github.com/dperini/ContentLoaded
http://javascript.nwbox.com/ContentLoaded (test)

это код, из которого команда jQuery создала свою реализацию.

Диего Перини
источник
1

Вот то, что я использую, это быстро и охватывает все основы, я думаю; работает для всего, кроме IE <9.

(() => { function fn() {
    // "On document ready" commands:
    console.log(document.readyState);
};  
  if (document.readyState != 'loading') {fn()}
  else {document.addEventListener('DOMContentLoaded', fn)}
})();

Это похоже на все случаи:

  • срабатывает немедленно, если DOM уже готов (если DOM не «загружается», а «интерактивен» или «завершен»)
  • если DOM все еще загружается, он устанавливает прослушиватель событий, когда DOM доступен (интерактивно).

Событие DOMContentLoaded доступно в IE9 и во всем остальном, поэтому я лично считаю, что это нормально. Перепишите объявление функции стрелки в обычную анонимную функцию, если вы не переносите свой код из ES2015 в ES5.

Если вы хотите дождаться загрузки всех ресурсов, отображения всех изображений и т. Д., Используйте вместо этого window.onload.

Olemak
источник
1

Если вам не нужно поддерживать очень старые браузеры, вот способ сделать это, даже если ваш внешний скрипт загружен с атрибутом async :

HTMLDocument.prototype.ready = new Promise(function(resolve) {
   if(document.readyState != "loading")
      resolve();
   else
      document.addEventListener("DOMContentLoaded", function() {
         resolve();
      });
});

document.ready.then(function() {
   console.log("document.ready");
});
user4617883
источник
0

Для IE9 +:

function ready(fn) {
  if (document.readyState != 'loading'){
    fn();
  } else {
    document.addEventListener('DOMContentLoaded', fn);
  }
}
Joaquinglezsantos
источник
0

Если вы загружаете jQuery в нижней части BODY, но у вас возникают проблемы с кодом, который записывает jQuery (<func>) или jQuery (document) .ready (<func>), проверьте jqShim на Github.

Вместо того, чтобы воссоздавать свою собственную функцию готовности документа, она просто удерживает функции до тех пор, пока не станет доступен jQuery, а затем продолжит работу с jQuery, как и ожидалось. Смысл перемещения jQuery в нижней части тела состоит в том, чтобы ускорить загрузку страницы, и вы все равно можете сделать это, вставив jqShim.min.js в заголовок вашего шаблона.

Я закончил тем, что написал этот код, чтобы переместить все скрипты в WordPress в нижний колонтитул, и именно этот код прокладки теперь находится прямо в заголовке.

Мэтт Пиледжи
источник
0

Попробуй это:

function ready(callback){
    if(typeof callback === "function"){
        document.addEventListener("DOMContentLoaded", callback);
        window.addEventListener("load", callback);
    }else{
        throw new Error("Sorry, I can not run this!");
    }
}
ready(function(){
    console.log("It worked!");
});

источник
Lol, ты собираешься запустить обратный вызов дважды
Андрей
0
function onDocReady(fn){ 
    $d.readyState!=="loading" ? fn():document.addEventListener('DOMContentLoaded',fn);
}

function onWinLoad(fn){
    $d.readyState==="complete") ? fn(): window.addEventListener('load',fn);
} 

onDocReady обеспечивает обратный вызов, когда HTML-домен готов к полному доступу / анализу / манипулированию.

onWinLoad обеспечивает обратный вызов, когда все загружено (изображения и т. д.)

  • Эти функции можно вызывать в любое время.
  • Поддерживает несколько «слушателей».
  • Будет работать в любом браузере.
Якоб Штернберг
источник
0
(function(f){
  if(document.readyState != "loading") f();
  else document.addEventListener("DOMContentLoaded", f);
})(function(){
  console.log("The Document is ready");
});
Дастин Пуассан
источник
Что это добавляет, что другие ответы нет?
Двонстон
Он использует автономное замыкание (не заполняет глобальную область «окна»), работает во всех браузерах и очень компактен. Я не вижу никаких других ответов, как это.
Дастин Пуассан
Это также работает даже после того, как DOM уже загружен (как делает jQuery.ready), что большинство из этих ответов не в состоянии сделать.
Дастин Пуассан
0

Большинство ванильных функций JS Ready НЕ учитывают сценарий, в котором устанавливается DOMContentLoadedобработчик после того, как документ уже загружен. Это означает, что функция никогда не будет работать . Это может произойти , если вы посмотрите в DOMContentLoadedпределах asyncвнешнего скрипта (<script async src="file.js"></script> ).

Код ниже проверяет DOMContentLoadedтолько, если документ еще readyStateне interactiveили complete.

var DOMReady = function(callback) {
  document.readyState === "interactive" || document.readyState === "complete" ? callback() : document.addEventListener("DOMContentLoaded", callback());
};
DOMReady(function() {
  //DOM ready!
});

Если вы хотите поддержать IE, а также:

var DOMReady = function(callback) {
    if (document.readyState === "interactive" || document.readyState === "complete") {
        callback();
    } else if (document.addEventListener) {
        document.addEventListener('DOMContentLoaded', callback());
    } else if (document.attachEvent) {
        document.attachEvent('onreadystatechange', function() {
            if (document.readyState != 'loading') {
                callback();
            }
        });
    }
};

DOMReady(function() {
  // DOM ready!
});
Значение NULL
источник
0

Я просто использую:

setTimeout(function(){
    //reference/manipulate DOM here
});

И в отличие document.addEventListener("DOMContentLoaded" //etcот самого верхнего ответа, он работает еще в IE9 - http://caniuse.com/#search=DOMContentLoaded указывает только на IE11.

Интересно, я наткнулся на это setTimeoutрешение в 2009 году: проверяет ли готовность DOM излишним?что, вероятно, можно было бы сформулировать немного лучше, поскольку я имел в виду «не слишком ли сложно использовать более сложные подходы различных сред для проверки готовности DOM».

Мое лучшее объяснение тому, почему этот метод работает, состоит в том, что, когда сценарий с таким setTimeout достигнут, DOM находится в середине анализа, поэтому выполнение кода в setTimeout откладывается до завершения этой операции.

Dexygen
источник