web-dev-qa-db-ja.com

jQueryに依存するJavaScriptウィジェットを未知の環境に埋め込む方法

JQueryに依存するJavaScriptウィジェットを開発しています。ウィジェットは、jQueryがすでにロードされているページにロードされる場合とロードされない場合があります。この場合に発生する多くの問題があります...

  1. WebページにjQueryがない場合は、自分のjQueryをロードする必要があります。ただし、これを行うと微妙なタイミングの問題があるようです。たとえば、jQueryの読み込みと実行が完了する前にウィジェットを読み込んで実行すると、_jQuery is not defined_エラーが発生します。

  2. WebページにjQueryがある場合は、通常、それを使用できます。ただし、jQueryのバージョンが古い場合は、自分のバージョンをロードしたいと思います。ただし、自分でロードする場合は、_$_変数を踏みつけないようにする必要があります。 jQuery.noConflict()を設定し、それらのスクリプトのいずれかが_$_に依存している場合、ページが壊れています。

  3. Webページで別のJavaScriptライブラリ(プロトタイプなど)を使用している場合、プロトタイプの_$_変数にも注意する必要がありました。

上記のすべてのため、jQueryに依存しない方が簡単に思えます。しかし、その道を進む前に、ウィジェットコードのほとんどを書き換える必要があるため、まずアドバイスを求めたかったのです。

タイミングのバグや、場合によっては_$_のバグを含む、私のコードの基本的な骨組みは次のとおりです。

_<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>
_

私のウィジェットの構造は次のとおりです。

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

上記のすべての環境で機能するウィジェットを実現するためのポインタまたはリソースがあれば、大いに評価されます。

61
robhudson

いくつかの回答とポインタを確認し、役立つjQueryハッカーを見つけた後、私は次のようなものになりました。

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

JQueryがまだ読み込まれていない場合は読み込まれ、コールバックにカプセル化されるため、ページ上の既存のjQueryと競合しません。また、最小バージョンが利用可能であることを確認するか、既知のバージョン(この場合はv1.3)をロードします。トリガーを作成する必要がある場合に備えて、jQueryがロードされたかどうかに関するコールバック(マイウィジェット)にブール値を送信します。そして、jQueryがロードされて初めて、ウィジェットが呼び出され、jQueryがウィジェットに渡されます。

97
robhudson

Alex Marandonによる How to build a web widget(using jQuery) を参照してください。

(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
5
Pavel Chuchuva

いくつかのjQueryプラグインも使用したい場合はどうなりますか?以下のように、プラグインの縮小バージョンを含む単一のファイルを作成して、それらをロードしても安全ですか? (この特定の例では、S3からロードされます。)

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

Document.write()を使用して、オプションでjQueryスクリプトをページに追加できますか?これにより、jQueryが同期して読み込まれるようになります。これを試して:

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

ウィジェットスクリプト内でjQueryチェックを実行する場合は、次のクロスブラウザーで動作すると思います。

(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);
 }
})()
1
Sean Hogan
1
micahwittman

私はこれが古いトピックであることを知っています...しかし、あなたのハックよりも速く何かを得ました。ウィジェットでお試しください

"init": function()

それは問題を解決します

0