$ (documento) .ready equivalente sin jQuery

2017

Tengo un script que usa $(document).ready , pero no usa nada más de jQuery. Me gustaría aclararlo eliminando la dependencia de jQuery.

¿Cómo puedo implementar mi propia $(document).readyfuncionalidad sin usar jQuery? Sé que usar window.onloadno será lo mismo, ya que se window.onloaddispara después de que se hayan cargado todas las imágenes, cuadros, etc.

FlySwat
fuente
296
... y definitivamente tampoco es la misma funcionalidad.
Joel Mueller
40
Como dice esta respuesta , si todo lo que desea de jQuery es $(document).ready, puede resolver ese problema fácilmente ejecutando su código en la parte inferior de la página en lugar de en la parte superior. HTML5Boilerplate utiliza este enfoque exacto.
Blazemonger
Hice mi llamada al final del documento y eso resuelve mi problema. Cuando se llama a la función, todo se carga.
IgniteCoders
Vale la pena echarle un vistazo: developer.mozilla.org/en-US/docs/Web/API/Document/readyState
Andrew

Respuestas:

1440

Hay un reemplazo basado en estándares, DOMContentLoadedque es compatible con más del 98% de los navegadores , aunque no IE8:

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

La función nativa de jQuery es mucho más complicada que solo window.onload, como se muestra a continuación.

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 );
}
Chad Grant
fuente
19
Una implementación de JavaScript simple y funcional aquí si alguien quiere código, simplemente puede
ingresar
44
El código listo para jQuery DOM parece estar simplificado: github.com/jquery/jquery/blob/master/src/core/ready.js
Jose Nobile
2
@JoseNobile porque cayeron mayor soporte de los navegadores
huysentruitw
16
Creo que todos estamos listos para pasar de IE8 ...;). Gracias por el enlace, @JoseNobile.
Con Antonakos
13
DOMContentLoaded no funcionará si el script se carga después. El documento JQuery ready se ejecuta siempre.
Jared Insel
343

Editar:

Aquí hay un reemplazo viable para 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
});

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

Otra buena función domReady aquí tomada de https://stackoverflow.com/a/9899701/175071


Como la respuesta aceptada estaba muy lejos de ser completa, uní una función "lista" jQuery.ready()basada en la fuente 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;
})();

Cómo utilizar:

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

No estoy seguro de cuán funcional es este código, pero funcionó bien con mis pruebas superficiales. Esto llevó bastante tiempo, así que espero que usted y otros puedan beneficiarse de ello.

PD .: sugiero compilarlo .

O puede usar http://dustindiaz.com/smallest-domready-ever :

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

o la función nativa si solo necesita admitir los nuevos navegadores (a diferencia de jQuery ready, esto no se ejecutará si agrega esto después de que la página se haya cargado)

document.addEventListener('DOMContentLoaded',function(){/*fun code to run*/})
Timo Huovinen
fuente
14
@TimoHuovinen Alternatives: Zepto.js (9.1 kb), Snack.js (8.1 kb), $ dom (2.3 kb) y 140 Medley (0.5 kb). Editar: También puedes echar un vistazo a Ender.
Frederik Krautwald
2
@FrederikKrautwald $ dom suena como lo que quisiera, pero no estoy seguro de si encaja bien Zepto también se ve muy prometedor, ¡gracias por compartir!
Timo Huovinen
@TimoHuovinen Si no has mirado a Ender, definitivamente deberías echar un vistazo, enderjs.com .
Frederik Krautwald
2
@Timo Huovinen: ¡Tu pregunta es muy, muy amplia! Cuando se creó jQuery, se ajustaba a muchos problemas de navegadores cruzados generados por navegadores que hoy en día son menos significativos. Hoy, "javascript only" es más fácil de lo que era. En este momento, crear una "gran compresión de 20 kb, que contenga todo" seguramente fue una buena idea por tantas razones que prefiero no enumerarlas todas.
dotpush
1
No me gusta esto Si la gente prefiere esta respuesta, pregúntese por qué quiere dejar jQuery en primer lugar. Es un poco inútil si solo va a extraer exactamente la misma funcionalidad con toda esa expansión de respaldo del navegador nuevamente en su paquete. ¿No es ese el objetivo de evitar jQuery en primer lugar?
Phil
208

Tres opciones:

  1. Si scriptes la última etiqueta del cuerpo, el DOM estaría listo antes de que se ejecute la etiqueta del script
  2. Cuando el DOM está listo, "readyState" cambiará a "complete"
  3. Ponga todo debajo del oyente de eventos 'DOMContentLoaded'

onreadystatechange

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

Fuente: MDN

DOMContentLoaded

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

Preocupado por los navegadores de la edad de piedra: vaya al código fuente de jQuery y use lareadyfunción. En ese caso, no está analizando + ejecutando toda la biblioteca, solo está haciendo una pequeña parte de ella.

Jhankar Mahbub
fuente
3
Este segundo ejemplo es mucho más elegante y sucinto que las respuestas marcadas. ¿Por qué este no estaba marcado como el correcto?
0112
2
Todavía +1 para lo de DOMContentLoaded, hizo exactamente lo que quería.
tripleee
1
onreadystatechange hizo el truco para mí ... necesitaba ejecutar algún script después de cargar asquenalmente jquery.
Abram
2
Al igual que para su información, # 1 no es del todo cierto. Es bastante posible que se cargue un script al final de la página antes de que se realice el DOM. Por eso los oyentes son superiores. Escuchan cuando el navegador está listo. Ponerlo al final es cruzar los dedos para que la carga del script sea más lenta de lo que el navegador puede procesar.
Machavity
1
esta variante también funcionará cuando el documento ya haya terminado de cargarse, actualice su (imo best) respuesta si puede: if (document.readyState == 'complete') {init (); } else {document.onreadystatechange = function () {if (document.readyState == 'complete') {init (); }}}
ZPiDER
87

Coloque su <script>/*JavaScript code*/</script>derecha antes del cierre </body> etiqueta de .

Es cierto que esto puede no ser adecuado para los propósitos de todos, ya que requiere cambiar el archivo HTML en lugar de simplemente hacer algo en el archivo JavaScript a la vez document.ready, pero aún así ...

robar
fuente
Me parece que hubo problemas de compatibilidad, como, dado que la página aún no está lista, no puede hacer esto o aquello en estos y esos navegadores. Lamentablemente no puedo recordar más claramente. Sin embargo, +1 para una forma lo suficientemente cercana en el 99% de todos los casos (y sugerido por Yahoo!).
Boldewyn el
77
En realidad, poner un elemento de script en la parte inferior de la página es una solución casi perfecta. Funciona entre navegadores y simula document.ready perfect. La única desventaja es que es (un poco) más molesto que usar un código inteligente, tendrá que pedirle al usuario del script que está creando que agregue un fragmento de script adicional para llamar a su función ready o init.
Stijn de Witt
@StijndeWitt - ¿Qué quieres decir con tener que llamar a una función init? Un script que usa document.ready no necesita otro código de cliente para llamarlo, es autónomo y el equivalente a aquel donde el código se incluye al final del cuerpo también puede ser autónomo y no requiere otro código para llamarlo tampoco.
nnnnnn
1
¿Por qué no colocar el script después de la etiqueta de cierre del cuerpo y antes de la </html>etiqueta de cierre ?
Charles Holbrow
1
@CharlesHolbrow Aunque todos los navegadores lo interpretarán correctamente, si desea que sea html válido, la htmletiqueta solo debe contener heady body.
Alvaro Montoro
66

La solución del pobre hombre:

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

checkLoad();  

Ver violín

Añadido este, un poco mejor, supongo, propio alcance y no recursivo

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

Ver violín

Jakob Sternberg
fuente
8
@PhilipLangford O simplemente colóquelo dentro de a setIntervaly elimine la recursión por completo.
Alex W
1
@Raveren, hmm tienes razón, estoy bastante seguro de que lo probé cuando lo publiqué. de todos modos, solo se volvió aún más simple, ahora solo se llama a la función, sin ajuste.
Jakob Sternberg
24
Esto no es sexy No lo siento. El uso de temporizadores / intervalos para detectar cosas puede "funcionar", pero si sigue programando así, cualquier proyecto más grande que valga la pena se hundirá. No hackear cosas como esta. Hazlo bien. Por favor. Este tipo de código daña el ecosistema de desarrollo porque hay una mejor solución y lo SABES.
dudewad
1
Creo que esta respuesta está mucho más cerca de dustindiaz.com/smallest-domready-ever Así que mejoré el script: jsfiddle.net/iegik/PT7x9
iegik
1
@ReidBlomquist Sí, y esta es una forma "incorrecta", y eso es lo que estoy señalando (aunque un poco inflexible, lo sé). Se podría decir que hacerlo mal de alguna manera está "ayudando" al ecosistema, pero el problema es que con la cantidad de código incorrecto que existe, la gente toma el código "bueno" porque no tienen la experiencia para conocerlo mejor NO ayuda al ecosistema, porque entonces tomarán ese código incorrecto y lo implementarán en una solución arquitectónica de producción real. Entonces, supongo, tendremos que diferir en la opinión sobre esta "falacia".
dudewad
34

Yo uso esto:

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

Nota: Esto probablemente solo funcione con navegadores más nuevos, especialmente estos: http://caniuse.com/#feat=domcontentloaded

Dustin Davis
fuente
13
IE9 y superior en realidad
Pascalius
Esto también funciona muy bien en los scripts de contenido de Chrome Extension si estaba enganchando el evento document_start o document_idle.
Volomike
21

Realmente, si solo le interesa Internet Explorer 9+ , este código sería suficiente para reemplazar jQuery.ready:

    document.addEventListener("DOMContentLoaded", callback);

Si te preocupa Internet Explorer 6 y algunos navegadores realmente extraños y raros, esto funcionará:

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();
        }
    }
},
Dan
fuente
18

Esta pregunta se hizo hace bastante tiempo. Para cualquiera que solo vea esta pregunta, ahora hay un sitio llamado "es posible que no necesite jquery" que desglosa, por nivel de soporte de IE requerido, toda la funcionalidad de jquery y proporciona algunas bibliotecas alternativas más pequeñas.

La secuencia de comandos preparada para documentos IE8 de acuerdo con usted podría no necesitar 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
fuente
Me pregunto por qué 'onreadystatechange'es necesario en lugar dedocument.attachEvent('onload', fn);
Luke
13

Recientemente estaba usando esto para un sitio móvil. Esta es la versión simplificada de John Resig de "Pro JavaScript Techniques". Depende de 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;
})();
James
fuente
13
Ten cuidado con este código. NO es equivalente a $ (documento). Listo. Este código activa la devolución de llamada cuando document.body está listo, lo que no garantiza que el DOM esté completamente cargado.
Karolis
12

Cross-browser (navegadores antiguos también) y una solución simple:

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

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

Mostrando alerta en jsfiddle

Pawel
fuente
Excepto si lleva más de 30 ms cargar el DOM, su código no se ejecutará.
Quelklef
1
@Quelklef que es setInterval no setTimeout
Pawel
11

La respuesta de jQuery fue muy útil para mí. Con un pequeño refactorio se ajustó bien a mis necesidades. Espero que ayude a alguien más.

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
fuente
en algunos navegadores, removeListenerse deberá llamar con el documento como contexto, es decir. removeListener.call(document, ...
Ron
9

Aquí está el fragmento de código más pequeño para probar DOM listo que funciona en todos los navegadores (incluso IE 8):

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

Mira esta respuesta .

Antara Roy
fuente
6

Simplemente agregue esto al final de su página HTML ...

<script>
    Your_Function();
</script>

Porque, los documentos HTML se analizan de arriba a abajo.

davefrassoni
fuente
77
¿Cómo sabes que DOM se construye cuando se ejecuta este código? ¿Incluyendo CSS cargado y analizado? La API del navegador DOMContentLoaded está diseñada para eso.
Dan
Realmente depende de lo que quiera hacer con js. Si realmente necesita ejecutar algo cuando la página ha terminado o no.
davefrassoni
5

Vale la pena mirar en Rock Solid addEvent () y http://www.braksator.com/how-to-make-your-own-jquery .

Aquí está el código en caso de que el sitio se caiga

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");});
Ben
fuente
El segundo enlace está roto.
Peter Mortensen el
4

Este código de navegador cruzado llamará a una función una vez que el DOM esté listo:

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

Así es como funciona:

  1. La primera línea domReadyllama al toStringmétodo de la función para obtener una representación en cadena de la función que pasa y la envuelve en una expresión que llama inmediatamente a la función.
  2. El resto de domReadycrea un elemento de script con la expresión y lo agrega albody documento.
  3. El navegador ejecuta etiquetas de script anexadas bodydespués de que el DOM esté listo.

Por ejemplo, si hace esto: domReady(function(){alert();});lo siguiente se agregará al bodyelemento:

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

Tenga en cuenta que esto solo funciona para funciones definidas por el usuario. Lo siguiente no funcionará:domReady(alert);

Max Heiber
fuente
3

¿Qué tal esta solución?

// 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();
};
Miguel
fuente
3
Puede usar addEventListener en la ventana con "carga". Los oyentes se ejecutan uno tras otro y no necesitan encadenarse manualmente.
Zaffy
1
Pero la carga es diferente a la lista. La 'carga' incluso ocurre antes de que el documento esté 'listo'. Un documento listo tiene su DOM cargado, una ventana cargada no necesariamente tiene el DOM listo. Buena respuesta, aunque
Mzn
1
@ Mzn: Creo que eso es al revés. Creo que el documento listo ocurre antes del evento de carga de la ventana. "En general, no es necesario esperar a que todas las imágenes se carguen completamente. Si el código se puede ejecutar antes, generalmente es mejor colocarlo en un controlador enviado al método .ready ()". ( api.jquery.com/load-event )
Tyler Rick el
esto anulará el resto de los eventos window.onload en la página y causaría problemas. debería agregar un evento encima del existente.
Teoman shipahi
El evento de carga puede suceder demasiado tarde. Es doloroso usarlo cuando depende de js / images externas de terceros ... Un servidor que no responde que no controlas y todo falla. Usar DOMContentLoaded no es solo una optimización, ¡también es más seguro!
dotpush
3

Siempre es bueno usar equivalentes de JavaScript en comparación con jQuery. Una razón es una biblioteca menos de la que depender y son mucho más rápidos que los equivalentes de jQuery.

Una referencia fantástica para los equivalentes de jQuery es http://youmightnotneedjquery.com/ .

En lo que respecta a su pregunta, tomé el siguiente código del enlace de arriba :) La única advertencia es que solo funciona con Internet Explorer 9 y posterior.

function ready(fn) {
    if (document.readyState != 'loading') {
        fn();
    }
    else {
        document.addEventListener('DOMContentLoaded', fn);
    }
}
Vatsal
fuente
3

El más mínimo y 100% de trabajo

Elegí la respuesta de PlainJS y está funcionando bien para mí. Se extiende DOMContentLoadedpara que pueda ser aceptado en todos los navegadores.


Esta función es el equivalente del $(document).ready()método de jQuery :

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

Sin embargo, a diferencia de jQuery, este código solo se ejecutará correctamente en los navegadores modernos (IE> 8) y no lo hará en caso de que el documento ya esté representado en el momento en que se inserta este script (por ejemplo, a través de Ajax). Por lo tanto, necesitamos extender esto un poco:

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

Esto cubre básicamente todas las posibilidades y es un reemplazo viable para el asistente jQuery.

Shivam Sharma
fuente
2

Encontramos una implementación de navegador cruzado rápida y sucia que puede hacer el truco para la mayoría de los casos simples con una implementación mínima:

window.onReady = function onReady(fn){
    document.body ? fn() : setTimeout(function(){ onReady(fn);},50);
};
malko
fuente
que es doc.body?
Nabi KAZ
2

Las soluciones setTimeout / setInterval presentadas aquí solo funcionarán en circunstancias específicas.

El problema aparece especialmente en versiones anteriores de Internet Explorer hasta 8.

Las variables que afectan el éxito de estas soluciones setTimeout / setInterval son:

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

El código original (Javascript nativo) para resolver este problema específico está aquí:

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

Este es el código a partir del cual el equipo de jQuery ha desarrollado su implementación.

Diego Perini
fuente
1

Esto es lo que uso, es rápido y cubre todas las bases, creo; funciona para todo excepto IE <9.

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

Esto parece captar todos los casos:

  • se dispara inmediatamente si el DOM ya está listo (si el DOM no está "cargando", sino "interactivo" o "completo")
  • si el DOM todavía se está cargando, configura un detector de eventos para cuando el DOM esté disponible (interactivo).

El evento DOMContentLoaded está disponible en IE9 y todo lo demás, por lo que personalmente creo que está bien usar esto. Vuelva a escribir la declaración de la función de flecha en una función anónima normal si no está transpilando su código de ES2015 a ES5.

Si desea esperar hasta que se carguen todos los activos, se muestren todas las imágenes, etc., use window.onload en su lugar.

Olemak
fuente
1

Si no tiene que admitir navegadores muy antiguos, esta es una forma de hacerlo incluso cuando su script externo está cargado con un atributo asíncrono :

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

Para IE9 +:

function ready(fn) {
  if (document.readyState != 'loading'){
    fn();
  } else {
    document.addEventListener('DOMContentLoaded', fn);
  }
}
Joaquinglezsantos
fuente
0

Si está cargando jQuery cerca de la parte inferior de BODY, pero tiene problemas con el código que escribe jQuery (<func>) o jQuery (document) .ready (<func>), consulte jqShim en Github.

En lugar de recrear su propia función de documento listo, simplemente mantiene las funciones hasta que jQuery esté disponible y luego continúa con jQuery como se esperaba. El punto de mover jQuery a la parte inferior del cuerpo es acelerar la carga de la página, y aún puede lograrlo al incluir jqShim.min.js en el encabezado de su plantilla.

Terminé escribiendo este código para mover todos los scripts en WordPress al pie de página, y solo este código de ajuste ahora se encuentra directamente en el encabezado.

Matt Pileggi
fuente
0

Prueba esto:

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

fuente
Lol vas a ejecutar la devolución de llamada dos veces
Andrew
0
function onDocReady(fn){ 
    $d.readyState!=="loading" ? fn():document.addEventListener('DOMContentLoaded',fn);
}

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

onDocReady proporciona una devolución de llamada cuando el dom HTML está listo para acceder / analizar / manipular por completo.

onWinLoad proporciona una devolución de llamada cuando todo se ha cargado (imágenes, etc.)

  • Estas funciones se pueden invocar cuando lo desee.
  • Soporta múltiples "oyentes".
  • Funcionará en cualquier navegador.
Jakob Sternberg
fuente
0
(function(f){
  if(document.readyState != "loading") f();
  else document.addEventListener("DOMContentLoaded", f);
})(function(){
  console.log("The Document is ready");
});
Dustin Poissant
fuente
¿Qué agrega esto que las otras respuestas no?
dwjohnston
Utiliza un cierre autónomo (no llena el alcance global de "ventana"), funciona en todos los navegadores y es muy compacto. No veo otras respuestas como esta.
Dustin Poissant
También funciona incluso después de que el DOM ya se haya cargado (como lo hace jQuery.ready), lo que la mayoría de estas respuestas no pueden hacer.
Dustin Poissant
0

La mayoría de las funciones de Vanilla JS Ready NO consideran el escenario en el que DOMContentLoadedse configura el controlador después de el documento ya está cargado, lo que significa que la función nunca se ejecutará . Esto puede suceder si busca DOMContentLoadeddentro de un asyncscript externo (<script async src="file.js"></script> ).

El siguiente código DOMContentLoadedsolo verifica si el documentoreadyState no está ya interactiveo complete.

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

Si también quieres admitir 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!
});
Nulo
fuente
0

Simplemente uso:

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

Y a diferencia document.addEventListener("DOMContentLoaded" //etcde la respuesta principal, funciona desde IE9: http://caniuse.com/#search=DOMContentLoaded solo indica tan recientemente como IE11.

Curiosamente me topé con esta setTimeoutsolución en 2009: ¿Verifica la preparación de la exageración DOM?, que probablemente podría haberse redactado un poco mejor, ya que quise decir "es excesivo usar los enfoques más complicados de varios marcos para verificar la disponibilidad del DOM".

Mi mejor explicación de por qué funciona esta técnica es que, cuando se alcanza el script con un setTimeout, el DOM está en el medio de ser analizado, por lo que la ejecución del código dentro del setTimeout se aplaza hasta que finalice la operación.

Dexygen
fuente