1

我有以下 JavaScript 片段,将从客户的网站引用。它使用 jQuery 1.5,所以我的问题是如果客户端已经加载了一个 jQuery 实例怎么办?还是替代的 JavaScript 库?

我正在使用 noConflict() 来尝试解决这个问题,但它似乎不起作用,我不知道为什么。任何帮助表示赞赏

主要问题是我收到一个错误返回,告诉我 jQueryMH 未定义,但我什至在设置 keepAlive 函数的时间间隔之前就明确定义了它。

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,但是我们遇到了以下问题,可能是因为它在每次函数运行时设置 noConflict(每 5 秒)

我设置的外部包含此 JS 脚本的测试页面已经加载了 jQuery 1.8,然后它加载了上面的脚本。因此,由于我的 noConflict,我希望 jQueryMH.fn.jquery 返回 1.5.0 和 jQuery.fn.jquery 返回 1.8;但是它们都返回 1.5.0,这意味着我的 noConflict 无法正常工作,因为 jQuery 不会保留为已加载到客户端网站的 1.8 版库。

4

3 回答 3

1

在加载第二个版本之前,您实际上需要noconflict一个版本的 jQuery,否则第二个版本将覆盖第一个版本。

除此之外,您的未定义变量问题是由于您在.noconflict函数内调用并将 jQuery 分配给仅在该函数范围内的备用变量而引起的。

我认为您需要首先执行以下操作:

var origjQuery = jQuery.noconflict();

然后像上面一样加载新的jQuery,然后noconflict

var jQueryMH = jQuery.noconflict();

然后恢复原来的jQuery:

var jQuery = origjQuery.noconflict();

在全局范围内执行上述所有操作。

于 2012-08-16T10:52:54.453 回答
1

我构建了 jQuery 的自定义构建,修改了将 jQuery 分配给全局变量的代码行。

具体来说,我将那行代码从:

window.jQuery = window.$ = jQuery;

window.myCustomJquery = jQuery;

这样,即使页面中包含 jQuery 脚本,我也可以毫无问题地注入我的自定义 jQuery 构建,并且无需密封/冻结实际的全局 jQuery 或不使用 .noConflict(),这两种解决方案都导致上面的问题。

于 2014-01-24T10:59:20.740 回答
0

在任何其他主机上注入脚本时,我实际上遇到了这个问题。

正如 Alnitak 所说,noConflict如果您先加载 jQuery,然后覆盖$变量,则可以工作,而不是相反。

我设法构建的解决方法使用了ECMAScript 5 中的Object.freezeObject.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);setInterval(keepAlive, 5000);,因为您的构造意味着每 5 秒重复一次对keepAlive 返回值(即undefined)的评估 - 而不是函数本身。

于 2012-08-16T11:27:54.950 回答