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


2016

У мене є сценарій, який використовує $(document).ready , але він не використовує нічого іншого з jQuery. Я хотів би полегшити її, видаливши залежність jQuery.

Як я можу реалізувати власну $(document).readyфункціональність без використання jQuery? Я знаю, що використання window.onloadне буде таким, як window.onloadпожежі після завантаження всіх зображень, кадрів тощо.


296
... а також точно не однаковий функціонал.
Джоель Мюллер

40
Як зазначено у цій відповіді , якщо все, що ви хочете від jQuery $(document).ready, ви можете вирішити цю проблему легко, запустивши свій код в самому нижній частині сторінки, а не вгорі. HTML5Boilerplate використовує такий точний підхід.
Blazemonger

3
Чому б не просто використовувати DOMContentLoaded? Це IE9 + caniuse.com/domcontentloaded developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded
Brock

Я зателефонував до останнього документа і вирішив свою проблему. Коли викликається функція, все завантажується.
IgniteCoders

Відповіді:


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 поточна робоча тут , якщо хто - то хоче , щоб код , який вони можуть просто кинути в: stackoverflow.com/questions/9899372 / ...
jfriend00

4
Готовий код jQuery DOM видається спрощеним: github.com/jquery/jquery/blob/master/src/core/ready.js
Жозе Нобіле

2
@JoseNobile, тому що вони відмовилися від старої підтримки браузера
huysentruitw

16
Я думаю, що ми всі готові перейти з IE8 ...;). Дякуємо за посилання, @JoseNobile.
Con Antonakos

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 kb), Snack.js (8,1 kb), $ dom (2,3 kb) та 140 Medley (0,5 kb). Редагувати: Ви також можете поглянути на Ендера.
Фредерік Краутвальд

2
@FrederikKrautwald $ dom звучить як те, що я хотів би, але не впевнений, чи відповідає він рахунку. Zepto також виглядає по-справжньому багатообіцяючим, дякую вам за спільний доступ!
Тімо Хуовінен

@TimoHuovinen Якщо ви ще не дивилися на Ендера, то обов'язково погляньте, enderjs.com .
Фредерік Краутвальд

2
@Timo Huovinen: Ваше запитання справді, дуже широке! Коли jQuery був створений, він підходив до безлічі проблем із перехресними веб-переглядачами, породженими браузерами, які сьогодні є менш значущими. Сьогодні "лише JavaScript" простіше, ніж це було. В цей час створення "великого стиснення 20 кбіт, яке містить все" було, безумовно, хорошою ідеєю з багатьох причин, я вважаю за краще не перелічувати їх усіх.
dotpush

1
Мені це не подобається. Якщо люди віддають перевагу цій відповіді, запитайте себе, чому ви хочете в першу чергу відмовитись від jQuery. Це трохи безглуздо, якщо ви просто збираєтеся витягнути такий самий функціонал, коли весь резервний пристрій браузера повернеться у ваш пакет. Чи не в цьому вся суть уникнення jQuery?
Філ

208

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

  1. Якщо script останній тег тіла, DOM буде готовий до виконання тегу сценарію
  2. Коли DOM буде готовий, "readyState" зміниться на "завершено"
  3. Покладіть усе під слухача подій "DOMContentLoaded"

на вжедержавнузміну

  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, вона робила саме те, що я хотів.
трійка

1
onreadystatechange зробив для мене хитрість ... потрібно було запустити якийсь сценарій після завантаження jquery async.
Аврам

2
Як і вигадка, №1 - це не зовсім так. Цілком можливо, що сценарій в кінці сторінки завантажується до того, як буде зроблено DOM. Ось чому слухачі вищі. Вони слухають, коли браузер виконаний. Якщо поставити його в кінці, це перехрестити пальці, щоб завантаження сценарію було повільніше, ніж браузер може надати.
Machavity

1
цей варіант також буде працювати, коли документ уже завершено завантаженням, будь ласка, оновіть свою (imo best) відповідь, якщо зможете: якщо (document.readyState == 'завершено') {init (); } else {document.onreadystatechange = функція () {if (document.readyState == 'завершено') {init (); }}}
ZPiDER

87

Розмістіть <script>/*JavaScript code*/</script>праворуч перед </body> тегом, що закривається .

Щоправда, це може не відповідати усім цілям, оскільки вимагає змінити HTML-файл, а не просто робити щось у файлі JavaScript a la document.ready, але все ж ...


Мені здається, були проблеми із сумісністю, наприклад, оскільки сторінка ще не готова, ви не можете зробити те чи інше в цих та тих браузерах. На жаль, я не можу згадати більш чітко. Тим не менш, +1 - спосіб, який є досить близьким у 99% усіх випадків (і пропонується Yahoo!).
Болдевін

7
Насправді, розміщення елемента сценарію внизу сторінки - це майже ідеальне рішення. Він працює крос-браузер і імітує document.ready ідеально. Єдиним недоліком є ​​те, що це (трохи) нав'язливіше, ніж використання якогось розумного коду, вам доведеться попросити користувача створеного сценарію додати додатковий фрагмент сценарію, щоб викликати вашу готову функцію чи функцію init.
Штійн де Вітт

@StijndeWitt - Що ви маєте на увазі про необхідність викликати функцію init? Сценарій, який використовує document.ready не потребує іншого коду клієнта для його виклику, він є автономним, і еквівалент тому, де код включений в кінці тіла, також може бути самостійним і не має вимагати іншого коду, щоб його також зателефонувати.
nnnnnn

1
Чому б не поставити скрипт після тега закриття тіла та перед </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 Або просто помістіть його всередину setIntervalта видаліть рекурсію повністю.
Alex 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, якщо ви підключили події 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();
        });
}

Цікаво, чому 'onreadystatechange'це потрібно, а неdocument.attachEvent('onload', fn);
Лука

13

Нещодавно я використовував це для мобільного сайту. Це спрощена версія Джона Резіга з "Про 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
Будьте обережні з цим кодом. НЕ еквівалентно $ (document). Вже. Цей код запускає зворотний виклик, коли document.body готовий, що не гарантує, що DOM повністю завантажений.
Кароліс

12

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

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

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

Показ сповіщення у jsfiddle


За винятком випадків, коли для завантаження DOM потрібно більше 30 мс, код не запускається.
Quelklef

1
@Quelklef це встановленоInterval not 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 )
}

у деяких браузерах 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 розбираються зверху вниз.


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. У браузері запущені теги сценаріїв, додані до bodyDOM, буде готово

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

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

Зауважте, що це працює лише для визначених користувачем функцій. Наступне не працює:domReady(alert);


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

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.


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


0

Якщо ви завантажуєте jQuery внизу BODY, але у вас виникають проблеми з кодом, який записує jQuery (<func>) або jQuery (документ). Вже (<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-dom готовий до повного доступу / розбору / маніпулювання.

onWinLoad забезпечує зворотний виклик, коли все завантажено (зображення тощо)

  • Ці функції можна викликати коли завгодно.
  • Підтримує декількох "слухачів".
  • Працює в будь-якому браузері.

0
(function(f){
  if(document.readyState != "loading") f();
  else document.addEventListener("DOMContentLoaded", f);
})(function(){
  console.log("The Document is ready");
});

Що це додає, що інші відповіді не відповідають?
dwjohnston

Він використовує автономне закриття (не заповнює глобальну область "вікна"), працює на всіх браузерах і дуже компактний. Я не бачу інших подібних відповідей.
Дастін Пуассан

Він також працює навіть після того, як 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!
});

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 відкладається до тих пір, поки ця операція не буде закінчена.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.