$ (document) .ready equivalente sem jQuery

2017

Eu tenho um script que usa $(document).ready, mas ele não usa mais nada do jQuery. Gostaria de aliviá-lo removendo a dependência do jQuery.

Como posso implementar minha própria $(document).readyfuncionalidade sem usar o jQuery? Eu sei que o uso window.onloadnão será o mesmo, pois os window.onloaddisparos depois que todas as imagens, quadros etc. foram carregados.

FlySwat
fonte
296
... e também definitivamente não é a mesma funcionalidade.
Joel Mueller
40
Como esta resposta indica, se tudo o que você quer do jQuery é $(document).ready, você pode resolver esse problema facilmente executando seu código na parte inferior da página e não na parte superior. O HTML5Boilerplate usa essa abordagem exata.
Blazemonger
3
Por que não usar apenas o DOMContentLoaded? É IE9 + caniuse.com/domcontentloaded developer.mozilla.org/pt-BR/docs/Web/Events/DOMContentLoaded
Brock
Fiz minha ligação no último documento e isso resolve meu problema. Quando a função é chamada, tudo é carregado.
IgniteCoders

Respostas:

1440

Há uma substituição baseada em padrões, DOMContentLoadedsuportada por mais de 98% dos navegadores , embora não o IE8:

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

A função nativa do jQuery é muito mais complicada do que apenas window.onload, como mostrado abaixo.

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
fonte
19
Uma implementação real de javascript simples e funcional aqui, se alguém quiser código, pode simplesmente
aparecer
4
O código pronto para jQuery DOM parece estar simplificado: github.com/jquery/jquery/blob/master/src/core/ready.js
Jose Nobile
2
@JoseNobile porque caiu mais velho suporte ao navegador
huysentruitw
16
Acho que estamos todos prontos para seguir em frente no IE8 ...;). Obrigado pelo link, @JoseNobile.
Con Antonakos
13
DOMContentLoaded não funcionará se o script for carregado posteriormente. O documento JQuery pronto é executado sempre.
Jared Insel
343

Editar:

Aqui está um substituto viável para o jQuery pronto

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

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

Outra boa função domReady aqui retirada de https://stackoverflow.com/a/9899701/175071


Como a resposta aceita estava muito longe de ser completa, juntei uma função "pronta" como jQuery.ready()baseada na fonte 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;
})();

Como usar:

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

Não tenho certeza de quão funcional é esse código, mas funcionou bem com meus testes superficiais. Demorou um pouco, então espero que você e outras pessoas possam se beneficiar disso.

PS .: Sugiro compilá- lo.

Ou você pode usar http://dustindiaz.com/smallest-domready-ever :

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

ou a função nativa se você precisar apenas oferecer suporte aos novos navegadores (ao contrário do jQuery pronto, isso não será executado se você o adicionar após o carregamento da página)

document.addEventListener('DOMContentLoaded',function(){/*fun code to run*/})
Timo Huovinen
fonte
14
Alternativas do @TimoHuovinen: Zepto.js (9,1 kb), Snack.js (8,1 kb), $ dom (2,3 kb) e 140 Medley (0,5 kb). Edit: Você também pode dar uma olhada no Ender.
Frederik Krautwald
2
@FrederikKrautwald $ dom parece o que eu gostaria, mas não tenho certeza se isso se encaixa na conta. O Zepto também parece muito promissor, obrigado por compartilhar!
Timo Huovinen 13/10
@TimoHuovinen Se você ainda não viu o Ender, definitivamente deveria dar uma olhada no enderjs.com .
Frederik Krautwald
2
@Timo Huovinen: Sua pergunta é muito, muito ampla! Quando o jQuery foi criado, ele apresentava muitos problemas entre navegadores gerados por navegadores que hoje são menos significativos. Hoje, "apenas javascript" é mais fácil do que era. No momento, a criação de um "grande 20kb compactado, que contém tudo" certamente foi uma boa idéia, por tantas razões que eu prefiro não listá-las todas.
dotpush
1
Eu não gosto disso. Se as pessoas preferirem essa resposta, pergunte a si mesmo por que você deseja descartar o jQuery em primeiro lugar. É um pouco inútil se você quiser extrair exatamente a mesma funcionalidade com todo esse retorno do navegador voltando ao seu pacote. Não é esse o objetivo de evitar o jQuery em primeiro lugar?
23417 Phil
208

Três opções:

  1. Se scriptfor a última tag do corpo, o DOM estará pronto antes da execução da tag de script
  2. Quando o DOM estiver pronto, "readyState" mudará para "complete"
  3. Coloque tudo no ouvinte de evento 'DOMContentLoaded'

onreadystatechange

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

Fonte: MDN

DOMContentLoaded

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

Preocupado com os navegadores da idade da pedra: Vá para o código fonte do jQuery e use areadyfunção Nesse caso, você não está analisando + executando a biblioteca inteira, mas apenas uma parte muito pequena.

Jhankar Mahbub
fonte
3
Este segundo exemplo é muito mais elegante e sucinto do que as respostas marcadas. Por que este não foi marcado como o correto?
0112
2
Ainda +1 na coisa DOMContentLoaded, ele fez exatamente o que eu queria.
tripleee
1
onreadystatechange fez o truque para mim ... precisava executar algum script após o carregamento assíncrono do jquery.
Abram
2
Assim como um FYI, o número 1 não é totalmente verdadeiro. É bem possível que um script no final da página seja carregado antes da conclusão do DOM. É por isso que os ouvintes são superiores. Eles escutam quando o navegador termina. Colocá-lo no final significa que o carregamento do script foi mais lento do que o navegador pode renderizar.
Machavity
1
essa variante também funcionará quando o carregamento do documento estiver concluído, atualize sua resposta (melhor) se você puder: if (document.readyState == 'complete') {init (); } else {document.onreadystatechange = function () {if (document.readyState == 'complete') {init (); }}}
ZPiDER
87

Coloque seu <script>/*JavaScript code*/</script>direito antes da </body> marca de fechamento .

É certo que isso pode não servir aos propósitos de todos, pois exige a alteração do arquivo HTML em vez de apenas fazer algo no arquivo JavaScript a la document.ready, mas ainda assim ...

roubar
fonte
Parece-me que houve problemas de compatibilidade, como, como a página ainda não está pronta, você não pode fazer isso ou aquilo nesses e nesses navegadores. Infelizmente, não consigo me lembrar com mais clareza. No entanto, +1 para uma maneira que seja suficientemente próxima em 99% de todos os casos (e sugerido pelo Yahoo!).
Boldewyn
7
Na verdade, colocar um elemento de script na parte inferior da página é uma solução quase perfeita. Ele funciona em vários navegadores e simula document.ready perfeito. A única desvantagem é que é (um pouco) mais invasiva do que usar algum código inteligente; você precisará solicitar ao usuário do script que está criando que adicione um fragmento extra de script para chamar sua função ready ou init.
Stijn de Witt
@StijndeWitt - O que você quer dizer com ter que chamar uma função init? Um script que usa document.ready não precisa de outro código de cliente para chamá-lo, é independente e o equivalente àquele em que o código é incluído no final do corpo também pode ser independente e não requer outro código para chamá-lo também.
Nnnnnn 21/10
1
Por que não colocar o script após a etiqueta do corpo de fechamento e antes da </html>etiqueta de fechamento ?
Charles Holbrow
1
@CharlesHolbrow Embora todos os navegadores o interpretem corretamente, se você quiser que ele seja html válido, a htmltag deve conter apenas heade body.
Alvaro Montoro
66

Solução do pobre homem:

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

checkLoad();  

Exibir violino

Adicionado este, um pouco melhor, eu acho, próprio escopo e não recursivo

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

Exibir violino

Jakob Sternberg
fonte
8
@ PhillipLangford Ou apenas coloque-o dentro de um setIntervale remova a recursão completamente.
Alex W
1
@ Raveren, hmm, você está certo, tenho certeza de que o testei quando o publiquei. de qualquer forma, ficou ainda mais simples, agora a função é chamada, sem quebra.
Jakob Sternberg
24
Isso não é sexy. Desculpe. O uso de temporizadores / intervalos para detectar coisas pode "funcionar", mas se você continuar programando assim, qualquer projeto maior vale a pena perder peso. Não corte coisas assim. Faça certo. Por favor. Esse tipo de código prejudica o ecossistema de desenvolvimento porque existe uma solução melhor e você a conhece.
Dudewad 17/07/2014
1
Eu acho que esta resposta muito mais perto de dustindiaz.com/smallest-domready-ever Então eu melhorou script: jsfiddle.net/iegik/PT7x9
iegik
1
@ReidBlomquist Sim, e esta é uma maneira "errada", e é isso que estou apontando (embora um pouco inflexível, eu sei). Você poderia dizer que, ao fazer algo errado, isso está de alguma forma "ajudando" o ecossistema, mas o problema é que, com a quantidade de código incorreto existente no mercado, as pessoas usam código "bom" porque não têm a experiência necessária para conhecer melhor. NÃO ajuda o ecossistema, porque eles pegam esse código incorreto e o implementam em uma solução arquitetônica de produção real. Então, acho que teremos que divergir de opinião sobre essa "falácia".
Dudewad
34

Eu uso isso:

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

Nota: Isso provavelmente funciona apenas com navegadores mais recentes, especialmente estes: http://caniuse.com/#feat=domcontentloaded

Dustin Davis
fonte
13
IE9 e acima, na verdade
Pascalius
Isso também funciona bem nos scripts de conteúdo da extensão do Chrome se você estiver conectando o evento document_start ou document_idle.
Volomike
21

Realmente, se você se preocupa apenas com o Internet Explorer 9+ , esse código seria suficiente para substituir jQuery.ready:

    document.addEventListener("DOMContentLoaded", callback);

Se você se preocupar com o Internet Explorer 6 e alguns navegadores realmente estranhos e raros, isso 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
fonte
18

Esta pergunta foi feita há muito tempo. Para quem está apenas vendo essa pergunta, agora existe um site chamado "talvez você não precise do jquery", que detalha - por nível de suporte do IE necessário - toda a funcionalidade do jquery e fornece algumas bibliotecas alternativas e menores.

Script pronto para documentos do IE8 de acordo com você pode não precisar do 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
fonte
Gostaria de saber por que o 'onreadystatechange'é necessário, em vez dedocument.attachEvent('onload', fn);
Lucas
13

Recentemente, eu estava usando isso para um site móvel. Esta é a versão simplificada de John Resig de "Pro JavaScript Techniques". Depende do 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
fonte
13
Tenha cuidado com este código. NÃO é equivalente a $ (documento) .ready. Esse código aciona o retorno de chamada quando document.body está pronto, o que não garante que o DOM esteja totalmente carregado.
Karolis
12

Navegador cruzado (navegadores antigos também) e uma solução simples:

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

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

Mostrando alerta em jsfiddle

Pawel
fonte
Exceto se levar mais de 30 ms para carregar o DOM, seu código não será executado.
Quelklef
1
@Quelklef que é setInterval não setTimeout
Pawel
11

A resposta do jQuery foi bastante útil para mim. Com um pouco de refinação, atendeu bem às minhas necessidades. Espero que ajude mais alguém.

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
fonte
em alguns navegadores, removeListenerserá necessário chamar o documento como contexto, ou seja. removeListener.call(document, ...
19413 Ron
9

Aqui está o menor trecho de código para testar o DOM pronto, que funciona em todos os navegadores (até o IE 8):

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

Veja esta resposta .

Antara Roy
fonte
6

Basta adicionar isso na parte inferior da sua página HTML ...

<script>
    Your_Function();
</script>

Porque, documentos HTML são analisados ​​de cima para baixo.

davefrassoni
fonte
7
Como você sabe que o DOM é criado quando esse código é executado? Incluindo CSS carregado e analisado? A API do navegador DOMContentLoaded foi projetada para isso.
Dan
Realmente depende do que ele quer fazer com js. Se ele realmente precisar executar algo quando a página terminar ou não.
Davefrassoni 13/05/19
5

Vale a pena procurar em Rock Solid addEvent () e http://www.braksator.com/how-to-make-your-own-jquery .

Aqui está o código, caso o site seja desativado

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
fonte
O segundo link está quebrado.
Peter Mortensen
4

Esse código entre navegadores chamará uma função assim que o DOM estiver pronto:

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

Veja como funciona:

  1. A primeira linha de domReadychamada chama o toStringmétodo da função para obter uma representação em seqüência da função que você passa e a envolve em uma expressão que chama imediatamente a função.
  2. O restante domReadycria um elemento de script com a expressão e o anexa ao bodydocumento.
  3. O navegador executa as tags de script anexadas bodyapós o DOM estar pronto.

Por exemplo, se você fizer isso domReady(function(){alert();});:, o seguinte será anexado ao bodyelemento:

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

Observe que isso funciona apenas para funções definidas pelo usuário. O seguinte não funcionará:domReady(alert);

Max Heiber
fonte
4

É ano 2020 e a <script>etiqueta tem deferatributo.

por exemplo:

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

especifica que o script é executado quando a página termina de analisar.

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

Mikser
fonte
3

Que tal esta solução?

// 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();
};
Mike
fonte
3
Você pode usar addEventListener na janela com "load". Os ouvintes são executados um após o outro e não precisam de encadeamento manualmente.
Zaffy
1
Mas a carga é diferente do que está pronta. O 'carregamento' até acontece antes que o documento esteja 'pronto'. Um documento pronto tem seu DOM carregado, uma janela carregada não necessariamente tem o DOM pronto. Porém, boa resposta
Mzn
1
@Mzn: Eu acho que é ao contrário. Acho que o documento pronto acontece antes do evento de carregamento da janela. "Em geral, não é necessário esperar que todas as imagens sejam totalmente carregadas. Se o código puder ser executado anteriormente, geralmente é melhor colocá-lo em um manipulador enviado ao método .ready ()." ( Api.jquery.com/load-event )
Tyler Rick
isso substituirá o restante dos eventos window.onload na página e causaria problemas. ele deve adicionar um evento sobre o existente.
Teoman shipahi
O evento de carregamento pode acontecer tarde demais. É doloroso usá-lo quando depende de js / imagens externas de terceiros ... Um servidor não responsivo que você não controla e tudo falha. Usar DOMContentLoaded não é apenas uma otimização, também é mais seguro!
dotpush
3

É sempre bom usar equivalentes JavaScript em comparação com o jQuery. Um dos motivos é a dependência de menos uma biblioteca e eles são muito mais rápidos que os equivalentes do jQuery.

Uma referência fantástica para os equivalentes do jQuery é http://youmightnotneedjquery.com/ .

No que diz respeito à sua pergunta, peguei o código abaixo no link acima :) Apenas uma ressalva é que ele funciona apenas com o Internet Explorer 9 e posterior.

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

O mínimo e 100% de trabalho

Eu escolhi a resposta do PlainJS e está funcionando bem para mim. Ele se estende DOMContentLoadedpara que possa ser aceito em todos os navegadores.


Esta função é equivalente ao $(document).ready()método jQuery :

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

No entanto, ao contrário do jQuery, esse código será executado corretamente apenas em navegadores modernos (IE> 8) e não será, caso o documento já seja renderizado no momento em que esse script é inserido (por exemplo, via Ajax). Portanto, precisamos estender um pouco isso:

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

Isso cobre basicamente todas as possibilidades e é um substituto viável para o auxiliar do jQuery.

Shivam Sharma
fonte
2

Encontramos uma implementação rápida e suja em vários navegadores, que pode fazer o truque para os casos mais simples com uma implementação mínima:

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

As soluções setTimeout / setInterval apresentadas aqui funcionarão apenas em circunstâncias específicas.

O problema aparece especialmente nas versões mais antigas do Internet Explorer até 8.

As variáveis ​​que afetam o sucesso dessas soluções setTimeout / setInterval são:

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

o código original (Javascript nativo) que resolve esse problema específico está aqui:

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

este é o código a partir do qual a equipe do jQuery criou sua implementação.

Diego Perini
fonte
1

Aqui está o que eu uso, é rápido e cobre todas as bases, eu acho; funciona para tudo, exceto IE <9.

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

Isso parece pegar todos os casos:

  • é acionado imediatamente se o DOM já estiver pronto (se o DOM não estiver "carregando", mas "interativo" ou "concluído")
  • se o DOM ainda estiver carregando, ele configurará um ouvinte de evento para quando o DOM estiver disponível (interativo).

O evento DOMContentLoaded está disponível no IE9 e em todo o resto, então eu pessoalmente acho que é bom usar isso. Reescreva a declaração da função de seta para uma função anônima regular, se você não estiver transpilando seu código do ES2015 para o ES5.

Se você quiser esperar até que todos os ativos sejam carregados, todas as imagens exibidas etc, use window.onload.

Olemak
fonte
1

Se você não precisa oferecer suporte a navegadores muito antigos, aqui está uma maneira de fazê-lo, mesmo quando seu script externo é carregado com o atributo async :

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

document.ready.then(function() {
   console.log("document.ready");
});
user4617883
fonte
0

Para o IE9 +:

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

Se você estiver carregando o jQuery perto da parte inferior do BODY, mas estiver tendo problemas com o código que grava o jQuery (<func>) ou jQuery (document) .ready (<func>), consulte o jqShim no Github.

Em vez de recriar sua própria função pronta para documento, ela simplesmente mantém as funções até que o jQuery esteja disponível e prossiga com o jQuery conforme o esperado. O objetivo de mover o jQuery para a parte inferior do corpo é acelerar o carregamento da página, e você ainda pode realizá-lo incluindo o jqShim.min.js na cabeça do seu modelo.

Acabei escrevendo esse código para mover todos os scripts do WordPress para o rodapé, e agora esse código de shim fica diretamente no cabeçalho.

Matt Pileggi
fonte
0

Tente o seguinte:

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

fonte
Lol você vai executar o retorno de chamada duas vezes
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 fornece um retorno de chamada quando o dom HTML está pronto para acessar / analisar / manipular completamente.

onWinLoad fornece um retorno de chamada quando tudo foi carregado (imagens etc.)

  • Essas funções podem ser chamadas sempre que você desejar.
  • Suporta vários "ouvintes".
  • Funcionará em qualquer navegador.
Jakob Sternberg
fonte
0
(function(f){
  if(document.readyState != "loading") f();
  else document.addEventListener("DOMContentLoaded", f);
})(function(){
  console.log("The Document is ready");
});
Dustin Poissant
fonte
O que isso acrescenta que as outras respostas não?
dwjohnston
Ele usa um fechamento independente (não preenche o escopo da "janela" global), funciona em todos os navegadores e é muito compacto. Não vejo outras respostas como essa.
Dustin Poissant
Também funciona mesmo depois que o DOM já foi carregado (como o jQuery.ready), o que a maioria dessas respostas falha.
Dustin Poissant
0

A maioria das funções vanilla JS Ready NÃO considera o cenário em que o DOMContentLoadedmanipulador é definido após o documento já estar carregado - o que significa que a função nunca será executada . Isso pode acontecer se você procurar DOMContentLoadeddentro de um asyncscript externo ( <script async src="file.js"></script>).

O código abaixo verifica DOMContentLoadedapenas se o documento readyStateainda não é interactiveou complete.

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

Se você deseja oferecer suporte ao IE também:

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
fonte
0

Eu simplesmente uso:

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

E, diferentemente document.addEventListener("DOMContentLoaded" //etcda resposta mais importante, funciona desde o IE9 - http://caniuse.com/#search=DOMContentLoaded indica apenas recentemente no IE11.

Curiosamente, me deparei com esta setTimeoutsolução em 2009: está verificando a disponibilidade do excesso de DOM? , que provavelmente poderia ter sido redigido um pouco melhor, pois eu quis dizer "é um exagero usar as abordagens mais complicadas de várias estruturas para verificar a disponibilidade do DOM".

Minha melhor explicação para por que essa técnica funciona é que, quando o script com um setTimeout é atingido, o DOM está sendo analisado, portanto a execução do código no setTimeout é adiada até que a operação seja concluída.

Dexygen
fonte