2176 votes

équivalent de $(document).ready sans jQuery

J'ai un script qui utilise $(document).ready mais il n'utilise rien d'autre de jQuery. J'aimerais l'alléger en supprimant la dépendance à jQuery.

Comment puis-je mettre en œuvre mon propre $(document).ready sans utiliser jQuery ? Je sais qu'en utilisant window.onload ne seront pas les mêmes, car window.onload se déclenche après que toutes les images, cadres, etc. ont été chargées.

299 votes

...et aussi certainement pas la même fonctionnalité.

42 votes

Comme cette réponse si tout ce que vous voulez de jQuery est $(document).ready vous pouvez résoudre ce problème facilement en exécutant votre code tout en bas de la page plutôt qu'en haut. HTML5Boilerplate utilise cette approche exacte.

5 votes

Pourquoi ne pas utiliser simplement le DOMContentLoaded ? C'est IE9+ caniuse.com/domcontentloaded developer.mozilla.org/fr/US/docs/Web/Events/DOMContentLoaded

1617voto

Chad Grant Points 16571

Il existe un remplacement basé sur des normes, DOMContentLoaded qui est soutenu par plus de 99% des navigateurs mais pas IE8 :

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

La fonction native de jQuery est beaucoup plus compliquée que le simple window.onload, comme illustré ci-dessous.

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

21 votes

Une implémentation en javascript fonctionne actuellement ici si quelqu'un veut du code, il peut juste le déposer : stackoverflow.com/questions/9899372/

4 votes

Le code jQuery DOM ready semble être simplifié : github.com/jquery/jquery/blob/master/src/core/ready.js

3 votes

JoseNobile parce qu'ils ont abandonné le support des anciens navigateurs.

357voto

Timo Huovinen Points 8283

Edit :

Voici un remplacement viable de jQuery ready

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

Tiré de https://plainjs.com/javascript/events/running-code-when-the-document-is-ready-15/

Une autre bonne fonction domReady ici tiré de https://stackoverflow.com/a/9899701/175071


Comme la réponse acceptée était très loin d'être complète, j'ai assemblé une fonction "prête" du type jQuery.ready() basé sur la source 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;
})();

Comment l'utiliser :

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

Je ne suis pas sûr de la fonctionnalité de ce code, mais il a bien fonctionné lors de mes tests superficiels. Cela m'a pris pas mal de temps, j'espère donc que vous et d'autres personnes pourront en profiter.

PS : Je suggère compilation de il.

Ou vous pouvez utiliser http://dustindiaz.com/smallest-domready-ever :

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

ou la fonction native si vous avez seulement besoin de supporter les nouveaux navigateurs (contrairement à jQuery ready, cette fonction ne fonctionnera pas si vous l'ajoutez après le chargement de la page).

document.addEventListener('DOMContentLoaded',function(){/*fun code to run*/})

15 votes

@TimoHuovinen Alternatives : Zepto.js (9.1 kb), Snack.js (8.1 kb), $dom (2.3 kb) et 140 Medley (0.5 kb). Edit : Vous pourriez aussi jeter un coup d'oeil à Ender.

2 votes

@FrederikKrautwald $dom ressemble à ce que je voudrais, mais je ne suis pas sûr qu'il convienne. Zepto semble également très prometteur, merci de le partager !

0 votes

@TimoHuovinen Si vous n'avez pas regardé Ender, vous devriez absolument le faire, enderjs.com .

214voto

KhanSharp Points 1754

Trois options :

  1. Si script est la dernière balise du corps, le DOM serait prêt avant l'exécution de la balise script.
  2. Lorsque le DOM est prêt, "readyState" devient "complete".
  3. Mettez tout sous l'écouteur d'événement 'DOMContentLoaded'.

changement d'état de lecture

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

Source : MDN

DOMContentLoaded

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

Préoccupé par les navigateurs de l'âge de pierre : Allez dans le code source de jQuery et utilisez la fonction ready fonction. Dans ce cas, vous n'êtes pas en train d'analyser et d'exécuter l'ensemble de la bibliothèque, vous n'en faites qu'une toute petite partie.

4 votes

Ce deuxième exemple est beaucoup plus élégant et succinct que les réponses marquées. Pourquoi celle-ci n'a-t-elle pas été marquée comme étant la bonne ?

3 votes

Toujours +1 pour le DOMContentLoaded, il a fait exactement ce que je voulais.

2 votes

Onreadystatechange a fait l'affaire pour moi ... j'avais besoin d'exécuter un script après le chargement asynchrone de jquery.

69voto

Jakob Sternberg Points 540

La solution du pauvre :

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

checkLoad();  

Voir le violon

J'ai ajouté celui-ci, un peu mieux je pense, avec une portée propre, et non récursif.

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

Voir le violon

0 votes

Il pourrait être intéressant de limiter les récursions avec une variable incrémentale dans la fonction.

9 votes

@PhilipLangford Ou simplement le mettre à l'intérieur d'un setInterval et supprimer complètement la récursion.

0 votes

Cela fonctionne-t-il pour quelqu'un ? J'ai dû changer function(){ alert("loaded!") a (function(){ alert("loaded!"))()

38voto

DustinDavis Points 7808

J'utilise ceci :

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

Note : Cela ne fonctionne probablement qu'avec les navigateurs les plus récents, notamment ceux-ci : http://caniuse.com/#feat=domcontentloaded

13 votes

IE9 et plus en fait

0 votes

Cela fonctionne également très bien dans les scripts de contenu de l'extension Chrome si vous accrochez l'événement document_start ou document_idle.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X