61 votes

Comment intégrer un widget Javascript dépendant de jQuery dans un environnement inconnu ?

Je développe un widget javascript qui dépend de jQuery. Le widget peut ou non être chargé sur une page où jQuery est déjà chargé. Il y a plusieurs problèmes qui se posent dans ce cas...

  1. Si la page Web ne contient pas de jQuery, je dois charger mon propre jQuery. Il semble toutefois y avoir un problème délicat de synchronisation lors de cette opération. Par exemple, si mon widget se charge et s'exécute avant que jQuery n'ait fini de se charger et de s'exécuter, j'obtiens une jQuery is not defined erreur.

  2. Si la page web contient jQuery, je peux généralement travailler avec. Toutefois, si la version de jQuery est ancienne, j'aimerais charger la mienne. Mais si je charge ma propre version, je dois le faire de manière à ne pas piétiner la page web. $ variable. Si je règle jQuery.noConflict() et tous leurs scripts dépendent de $ alors je viens de casser leur page.

  3. Si la page Web utilise une autre bibliothèque javascript (par exemple, prototype), je devais tenir compte de l'utilisation de la bibliothèque prototype. $ variable également.

En raison de tout ce qui précède, il semble plus facile de ne pas dépendre de jQuery. Mais avant de m'engager dans cette voie, qui impliquera surtout de réécrire le code de mes widgets, je voulais d'abord vous demander conseil.

Le squelette de base de mon code, y compris le bogue de synchronisation et parfois $ bugs, suit :

<script type="text/javascript" charset="utf-8">
// <![CDATA
 if (typeof jQuery === 'undefined') {
  var head = document.getElementsByTagName('head')[0];
  var script = document.createElement('script');
  script.type = 'text/javascript';
  script.src = '{{ URL }}/jquery.js';
  head.appendChild(script);
 }
// ]]>
</script>
<script type="text/javascript" src="{{ URL }}/widget.js"></script>

Mon widget a la structure suivante :

(function($) {
 var mywidget = {
  init: function() {
   ...
  }
 };
 $(document).ready(function() {
   mywidget.init();
 });
})(jQuery);

Si vous avez des conseils ou des ressources pour créer un widget qui puisse fonctionner dans tous les environnements mentionnés, nous vous en remercions.

97voto

robhudson Points 1760

Après avoir passé en revue quelques réponses et pointeurs, et trouvé quelques hackers jQuery utiles, j'ai fini par obtenir quelque chose comme ce qui suit :

(function(window, document, version, callback) {
    var j, d;
    var loaded = false;
    if (!(j = window.jQuery) || version > j.fn.jquery || callback(j, loaded)) {
        var script = document.createElement("script");
        script.type = "text/javascript";
        script.src = "/media/jquery.js";
        script.onload = script.onreadystatechange = function() {
            if (!loaded && (!(d = this.readyState) || d == "loaded" || d == "complete")) {
                callback((j = window.jQuery).noConflict(1), loaded = true);
                j(script).remove();
            }
        };
        (document.getElementsByTagName("head")[0] || document.documentElement).appendChild(script);
    }
})(window, document, "1.3", function($, jquery_loaded) {
    // Widget code here
});

Cela chargera jQuery s'il n'est pas déjà chargé et l'encapsulera dans le callback afin qu'il n'entre pas en conflit avec un jQuery préexistant sur la page. Elle vérifie également qu'une version minimale est disponible ou bien charge une version connue -- dans ce cas, v1.3. Il envoie une valeur booléenne au callback (mon widget) pour savoir si jQuery a été chargé ou non, au cas où des déclenchements seraient nécessaires. Et ce n'est qu'une fois que jQuery est chargé qu'il appelle mon widget, en lui passant jQuery.

5voto

Pavel Chuchuva Points 12220

Ver Comment construire un widget web (en utilisant jQuery) par Alex Marandon.

(function() {

// Localize jQuery variable
var jQuery;

/******** Load jQuery if not present *********/
if (window.jQuery === undefined || window.jQuery.fn.jquery !== '1.4.2') {
    var script_tag = document.createElement('script');
    script_tag.setAttribute("type","text/javascript");
    script_tag.setAttribute("src",
        "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js");
    if (script_tag.readyState) {
      script_tag.onreadystatechange = function () { // For old versions of IE
          if (this.readyState == 'complete' || this.readyState == 'loaded') {
              scriptLoadHandler();
          }
      };
    } else { // Other browsers
      script_tag.onload = scriptLoadHandler;
    }
    // Try to find the head, otherwise default to the documentElement
    (document.getElementsByTagName("head")[0] || document.documentElement).appendChild(script_tag);
} else {
    // The jQuery version on the window is the one we want to use
    jQuery = window.jQuery;
    main();
}

/******** Called once jQuery has loaded ******/
function scriptLoadHandler() {
    // Restore $ and window.jQuery to their previous values and store the
    // new jQuery in our local jQuery variable
    jQuery = window.jQuery.noConflict(true);
    // Call our main function
    main(); 
}

/******** Our main function ********/
function main() { 
    jQuery(document).ready(function($) { 
        // We can use jQuery 1.4.2 here
    });
}

})(); // We call our anonymous function immediately

2voto

cailinanne Points 4737

Et si vous voulez aussi utiliser des plugins jQuery ? Est-il sûr de créer un seul fichier avec les versions réduites des plugins, et de les charger, comme ci-dessous ? (Chargé depuis S3, dans cet exemple particulier).

(function(window, document, version, callback) {
  var j, d;
  var loaded = false;
  if (!(j = window.jQuery) || version > j.fn.jquery || callback(j, loaded)) {
    var script = document.createElement("script");
    script.type = "text/javascript";
    script.src = "http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js";
    script.onload = script.onreadystatechange = function() {
        if (!loaded && (!(d = this.readyState) || d == "loaded" || d == "complete")) {
            window.jQuery.getScript('http://mydomain.s3.amazonaws.com/assets/jquery-plugins.js', function() {
              callback((j = window.jQuery).noConflict(1), loaded = true);
              j(script).remove();
            });
        }
    };
    document.documentElement.childNodes[0].appendChild(script)
  }
})(window, document, "1.5.2", function($, jquery_loaded) {
  // widget code goes here
});

1voto

micahwittman Points 6943

1voto

Sean Hogan Points 1750

Pouvez-vous utiliser document.write() pour ajouter facultativement le jQuery script à la page ? Cela devrait forcer jQuery à se charger de manière synchrone. Essayez ceci :

<script type="text/javascript" charset="utf-8">
// <![CDATA
 if (typeof jQuery === 'undefined') {
  document.write('<script src="{{ URL }}/jquery.js"><' + '/script>');
 }
// ]]>
</script>
<script type="text/javascript" src="{{ URL }}/widget.js"></script>

Si vous voulez faire la vérification jQuery à l'intérieur de votre widget script alors je crois que ce qui suit fonctionne cross-browser :

(function() {
 function your_call($) {
  // your widget code goes here
 }
 if (typeof jQuery !== 'undefined') your_call(jQuery);
 else {
  var head = document.getElementsByTagName('head')[0];
  var script = document.createElement('script');
  script.type = 'text/javascript';
  script.src = '{{ URL }}/jquery.js';
  var onload = function() {
   if (!script.readyState || script.readyState === "complete") your_call(jQuery);
  }
  if ("onreadystatechange" in script) script.onreadystatechange = onload;
  else script.onload = onload;
  head.appendChild(script);
 }
})()

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