1

クライアントの Web サイトから参照される次の JavaScript があります。jQuery 1.5 を使用しているため、クライアントに既に jQuery のインスタンスがロードされている場合はどうなるでしょうか。それとも代替の JavaScript ライブラリですか?

これを回避するために noConflict() を使用していますが、うまくいかないようで、その理由がわかりません。どんな助けでも大歓迎です

主な問題は、jQueryMH が未定義であることを示すエラーが返されることですが、keepAlive 関数で間隔を設定する前に、jQueryMH を明確に定義しています。

var head    = document.getElementsByTagName('head')[0];
var script  = document.createElement('script');
script.src  = '//ajax.googleapis.com/ajax/libs/jquery/1.5.0/jquery.min.js';
script.type = 'text/javascript';
script.onload = script.onreadystatechange = function() {
                                                var jQueryMH = jQuery.noConflict(true);
                                                setInterval(keepAlive(), 5000);
                                            };
head.appendChild(script);
function keepAlive() {
    var mhProtocol      = ((document.location.protocol == "https:") ? "https://" : "http://");
    var randomNumber    = Math.floor(Math.random()*10000);
    var mhVisitorId     = document.cookie.match('mhVisitorId=(.*?)(;|$)');
    var urlParamString  = "";
    if(mhVisitorId) { 
        urlParamString = "&mhVisitorId=" + encodeURIComponent(mhVisitorId[1]); 
    }
    var mhUrl = "www.urlishere.com";
    //var jQueryMH = jQuery.noConflict();
    jQueryMH.ajax({
        url: mhUrl,
        dataType: 'jsonp'
    });
}

これ以外に、関数自体に noConflict() を設定しようとしましたが、これは機能し、jQueryMH を参照できますが、おそらく関数が実行されるたびに (5 秒ごとに) noConflict を設定しているため、次の問題があります。

この JS スクリプトを外部に含むように設定したテスト ページには、既に jQuery 1.8 が読み込まれており、その後、上記のスクリプトが読み込まれます。したがって、noConflict のため、jQueryMH.fn.jquery が 1.5.0 を返し、jQuery.fn.jquery が 1.8 を返すことを期待します。ただし、どちらも 1.5​​.0 を返します。これは、クライアントの Web サイトに既にロードされているバージョン 1.8 ライブラリとして jQuery が保持されないため、noConflict が機能していないことを意味します。

4

3 に答える 3

1

2 番目のバージョンをロードする前に、実際には jQuerynoconflict最初のバージョンが必要です。そうしないと、2 番目のバージョンが最初のバージョンを上書きしてしまいます。

それとは別に、関数内で呼び出し、その関数内でのみスコープ内.noconflictにある代替変数にjQueryを割り当てるため、未定義の変数の問題が発生します。

最初に行う必要があると思います:

var origjQuery = jQuery.noconflict();

次に、上記のように新しい jQuery をロードしますnoconflict

var jQueryMH = jQuery.noconflict();

元の jQuery を復元します。

var jQuery = origjQuery.noconflict();

上記のすべてをグローバル スコープで実行します。

于 2012-08-16T10:52:54.453 に答える
0

他のホストにスクリプトを挿入するときに、実際にこの問題が発生しました。

Alnitak が述べたように、noConflict最初に jQuery をロードしてから$変数を上書きすると機能しますが、その逆ではありません。

私が構築した回避策は、ECMAScript 5 のメソッドObject.freezeとメソッドを使用しています。Object.seal

問題は、既存のサイト ( など$) で上書きしたい変数を、最終的にフリーズするオブジェクトにコピーすることです。
変数を書き換える前 (jQuery をロードする前) にそのオブジェクトをフリーズすることで、元の変数 (この場合は$) のコピーがオブジェクトに保存され、他のスクリプトによって変更されないようにすることができます。
目的のライブラリをロードした後、凍結したオブジェクト プロパティをグローバル オブジェクトにコピーするだけで、ホスト環境はそのまま残ります。
わかりやすくするためのサンプルコードを次に示します。

var aux = {'jQuery' : window.jQuery};
if(Object.freeze)
    // prevent anyone from deleting any of the `aux` props
    Object.freeze(aux);
if(Object.seal)
    // prevent anyone from altering the initial jQuery
    // this is necessary because `aux.jQuery` is a copy by reference of the
    // window.jQuery, thus any modification in the global jQuery object
    // would be reflected in our jQuery copy
    Object.seal(aux.jQuery);

var head    = document.getElementsByTagName('head')[0];
var script  = document.createElement('script');
script.src  = '//ajax.googleapis.com/ajax/libs/jquery/1.5.0/jquery.min.js';
script.type = 'text/javascript';
script.onload = script.onreadystatechange = function() {
    var jQueryMH = jQuery.noConflict(true);
    // restore the initial jquery
    window.jQuery = aux.jQuery;
    alert(jQuery === jQueryMH);
};

もちろん、機能を拡張して、使用する他のライブラリに使用することもできます。

var __globalLibs = {},
    libsThatYouWantToPreserve = '$ jQuery otherLib'.split(' '),
    key;

for(var i=0,l=libsThatYouWantToPreserve.length;i<l;i++)
    {
        key = libsThatYouWantToPreserve[i];
        // copy the contents of the global variable into your object
        __globalLibs[key] = window[key];
        if(Object.seal)
            Object.seal(__globalLibs[key]);
    }

if(Object.freeze)
    Object.freeze(__globalLibs);

// load jquery and all the other libs

// make copies of your update libs

var jQueryMH = jQuery;

// and then restore the initial variables to the global context
 for(var i=0,l=libsThatYouWantToPreserve.length;i<l;i++)
    {
        key = libsThatYouWantToPreserve[i];
        // copy the contents of the global variable into your object
        window[key] = __globalLibs[key];
    }

// after that, you can just delete your object
delete window.__globalLibs; 

唯一の欠点は、IE8 以前ではサポートされていないことです。
お役に立てれば!

PS : おそらく に変更する必要がありsetInterval(keepAlive(), 5000);ます。これは、構造が戻り値(関数自体ではなく) の評価を 5 秒ごとsetInterval(keepAlive, 5000);に繰り返すことを意味するためです。keepAlive undefined

于 2012-08-16T11:27:54.950 に答える