javascript - vanilla - js on page ready




$(document).ready équivalent sans jQuery (20)

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

Comment puis-je implémenter ma propre fonctionnalité $(document).ready sans utiliser jQuery? Je sais que l'utilisation de window.onload ne sera pas la même, car window.onload déclenchera après le window.onload de toutes les images, cadres, etc.


Ajoutez simplement ceci au bas de votre page HTML ...

<script>
    Your_Function();
</script>

Parce que, les documents HTML sont analysés par haut-bas.


Ce code croisé appellera une fonction une fois que le DOM sera prêt:

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

Voici comment cela fonctionne:

  1. La première ligne de domReady appelle la méthode toString de la fonction pour obtenir une représentation sous forme de chaîne de la fonction que vous transmettez et l'enveloppe dans une expression qui appelle immédiatement la fonction.
  2. Le reste de domReady crée un élément de script avec l'expression et l'ajoute au body du document.
  3. Le navigateur exécute des balises de script ajoutées au body après que le DOM est prêt.

Par exemple, si vous faites ceci: domReady(function(){alert();}); , ce qui suit sera ajouté à l'élément body :

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

Notez que cela ne fonctionne que pour les fonctions définies par l'utilisateur. Ce qui suit ne fonctionnera pas: domReady(alert);


Cross-browser (anciens navigateurs aussi) et une solution simple:

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

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

Affichage d'alerte dans jsfiddle


Il est intéressant de regarder dans Rock Solid addEvent () et http://www.braksator.com/how-to-make-your-own-jquery .

Voici le code au cas où le site tombe en panne

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

Il existe un remplacement basé sur les standards, DOMContentLoaded qui est supporté par plus de 98% des navigateurs , mais pas IE8:

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

La fonction native de jQuery est beaucoup plus compliquée que juste 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 );
}

J'utilise ceci:

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

Note: Cela ne fonctionne probablement qu'avec les nouveaux navigateurs, en particulier ceux-ci: http://caniuse.com/#feat=domcontentloaded


Je l'utilisais récemment pour un site mobile. Ceci est la version simplifiée de John Resig de "Pro JavaScript Techniques". Cela dépend 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;
})();

La fonction prête dans jQuery fait un certain nombre de choses. Franchement, je ne vois pas l'intérêt de le remplacer à moins que vous ayez une sortie incroyablement petite de votre site web. jQuery est une bibliothèque minuscule, et il gère toutes sortes de choses que vous aurez besoin plus tard.

Quoi qu'il en soit, il est bindReady le bindReady ici, ouvrez jQuery et regardez la méthode bindReady .

It starts by calling either document.addEventListener("DOMContentLoaded") or document.attachEvent('onreadystatechange') depending on the event model, and goes on from there.


La solution de l'homme pauvre:

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

checkLoad();  

Voir le violon

Ajouté celui-ci, un peu mieux je suppose, propre portée, et non récursif

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

Voir le violon


Les solutions setTimeout / setInterval présentées ici ne fonctionneront que dans des circonstances spécifiques.

Le problème apparaît en particulier dans les anciennes versions d'Internet Explorer jusqu'à 8.

Les variables affectant le succès de ces solutions setTimeout / setInterval sont:

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

le code original (Javascript natif) résolvant ce problème spécifique est ici:

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

c'est le code à partir duquel l'équipe jQuery a construit son implémentation.


Nous avons trouvé une implémentation cross-browser rapide et sale qui pourrait faire l'affaire pour les cas les plus simples avec une implémentation minimale:

window.onReady = function onReady(fn){
    document.body ? fn() : setTimeout(function(){ onReady(fn);},50);
};

Placez votre <script>/*JavaScript code*/</script> juste avant la </body> fermeture </body> .

Certes, cela peut ne pas convenir aux besoins de tout le monde car il faut changer le fichier HTML plutôt que de simplement faire quelque chose dans le fichier JavaScript a la document.ready , mais quand même ...


Trois options:

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

onreadystatechange

  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 au code source jQuery et utilisez la fonction ready . Dans ce cas, vous n'êtes pas en train d'analyser + en exécutant toute la bibliothèque dont vous ne faites qu'une toute petite partie.


Voici ce que j'utilise, c'est rapide et couvre toutes les bases je pense; fonctionne pour tout sauf IE <9.

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

Cela semble capturer tous les cas:

  • se déclenche immédiatement si le DOM est déjà prêt (si le DOM n'est pas en train de "charger" mais "interactif" ou "complet")
  • si le DOM est encore en train de charger, il configure un écouteur d'événement pour quand le DOM est disponible (interactif).

L'événement DOMContentLoaded est disponible dans IE9 et tout le reste, donc je pense personnellement que c'est OK pour l'utiliser. Réécrivez la déclaration de fonction de flèche à une fonction anonyme régulière si vous ne transpilez pas votre code de ES2015 à ES5.

Si vous voulez attendre que tous les éléments soient chargés, toutes les images affichées, etc., utilisez plutôt window.onload.


Vraiment, si vous vous intéressez uniquement à Internet Explorer 9+ , ce code suffirait à remplacer jQuery.ready :

    document.addEventListener("DOMContentLoaded", callback);

Si vous vous inquiétez d' Internet Explorer 6 et de certains navigateurs vraiment étranges et rares, cela fonctionnera:

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

Edit of the edit of @duskwuff to support Internet Explorer 8 too. The difference is a new call to the function test of the regex and the setTimeout with an anonymous function.

Also, I set the timeout to 99.

function ready(f){/in/.test(document.readyState)?setTimeout(function(){ready(f);},99):f();}

If you are loading jQuery near the bottom of BODY, but are having trouble with code that writes out jQuery(<func>) or jQuery(document).ready(<func>), check out jqShim on Github.

Rather than recreate its own document ready function, it simply holds onto the functions until jQuery is available then proceeds with jQuery as expected. The point of moving jQuery to the bottom of body is to speed up page load, and you can still accomplish it by inlining the jqShim.min.js in the head of your template.

I ended up writing this code to make moving all the scripts in WordPress to the footer, and just this shim code now sits directly in the header.


If you don't have to support very old browsers, here is a way to do it even when your external script is loaded with async attribute:

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

This approach is the shortest way I can think of.

The solution based on the DOMContentLoaded event only works if the script is loaded before the document, whereas the lazy check suggested here ensures the code is executed always, even in scripts loaded dynamically later on, exactly as the JQuery's document ready.

This code is compatible with all browsers (including some legacy, down to IE6 and Safari for Windows).

(function ready() {
    if (!document.body) {setTimeout(ready, 50); return;}
    // Document is ready here
})();

This was a good https://.com/a/11810957/185565 poor man's solution. One comment considered a counter to bail out in case of emergency. This is my modification.

function doTheMagic(counter) {
  alert("It worked on " + counter);
}

// wait for document ready then call handler function
var checkLoad = function(counter) {
  counter++;
  if (document.readyState != "complete" && counter<1000) {
    var fn = function() { checkLoad(counter); };
    setTimeout(fn,10);
  } else doTheMagic(counter);
};
checkLoad(0);




jquery