使用 getScript 在页面上使用多个版本的 jQuery 导入插件

Posted

技术标签:

【中文标题】使用 getScript 在页面上使用多个版本的 jQuery 导入插件【英文标题】:using getScript to import plugin on page using multiple versions of jQuery 【发布时间】:2011-02-19 07:21:56 【问题描述】:

我正在使用 jQuery 1.2.6 的页面上开发应用程序,但我想为我的应用程序使用 jQuery 1.4.2。我真的不喜欢像这样使用多个版本的 jQuery,但是页面上的副本(1.2.6)是我无法控制的。我决定像这样隔离我的代码:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html><head>
<script type="text/javascript" src="jquery-1.2.6.min.js>
<script type="text/javascript" src="pageStuff.js"></script>
</head>
<body>
Welcome to our page.
<div id="app">
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
    <script type="text/javascript" src="myStuff.js"></script>
</div>
</body></html>

文件 myStuff.js 有我自己的代码,应该使用 jQuery 1.4.2,它看起来像这样:

(function($)   //wrap everything in function to add ability to use $ var with noConflict
    var jQuery = $;
    //my code
)(jQuery.noConflict(true));

这是一个极其简化的版本,但我希望你能理解我所做的事情。有一段时间,一切正常。但是,我决定在单独的文件中使用 jQuery 插件。我测试了它,它的行为很有趣。经过一番实验,我发现该插件使用的是旧版本的jQuery,而我希望它使用新版本。有谁知道如何从将代码包装在 myStuff.js 中的函数中的上下文中导入和运行 js 文件?

如果这对任何人都很重要,以下是我如何知道插件正在使用旧版本,以及我为解决问题所做的工作:我创建了一个名为 test.js 的文件,其中包含以下行:

alert($.fn.jquery);

我尝试在 myStuff.js 下方以通常包含外部 Javascript 的方式在脚本标记中引用该文件,结果正如我预期的那样,它是 1.2.6。然后我去掉了那个脚本标签并将这一行放在 myStuff.js 中:

$.getScript("test.js");

它仍然以 1.2.6 的形式返回。这并不令人意外——根据jQuery's documentation 的说法,以这种方式包含的脚本是在全局上下文中执行的。然后我尝试这样做:

var testFn = $.proxy($.getScript, this);
testFn("test.js");

它仍然以 1.2.6 的形式返回。经过一番修改,我发现“this”关键字指的是窗口,我假设它是指全局上下文。我正在寻找一些东西来代替“this”来引用封闭函数的上下文,或者以其他方式使文件中的代码从封闭函数运行。我注意到,如果我复制并粘贴代码,它可以正常工作,但它是一个在许多地方使用的大插件,我不想让我的文件与他们的代码混淆。我没主意了。其他人知道怎么做吗?

【问题讨论】:

简而言之,这么多,很多的东西都没有考虑到这一点,你不能运行2个版本的jQuery并且让你的插件开箱即用,拥有window.jQuery 的人将赢得这场战斗。另外...您将客户端的 javascript 负载加倍,您应该找到解决此问题的不同方法。 您应该关闭所有带有&lt;/script&gt;&lt;script&gt; 标签。以防万一您遇到一些语法问题(仅基于您上面提供的代码) 你要插入哪个插件 我在上面的示例中添加了结束脚本标签。我一直在我的项目中使用结束脚本标签。问题与此无关。我正在尝试使用 jCarousel 插件。你可以在sorgalla.com/jcarousel看到它。 【参考方案1】:

当您加载 jQuery 时,它所做的只是创建一个根 jQuery 对象并设置 window.jQuerywindow.$ 指向它。所以你可以简单地加载旧的jQuery,将window.jQuery复制到window.jQuery126,加载新的jQuery,将window.jQuery复制到window.jQuery142,然后在你想要插件使用时更改window.jQuerywindow.$其他版本。

这是一个丑陋且不稳定的黑客,但它应该可以工作,只要

    为非默认版本编写的所有代码都用(function($)...)($) 封装(适当的jQuery 插件应该这样做,您可以轻松地为自己的代码确保它) 与不同 jQuery 版本一起使用的脚本不会相互混淆(例如一个绑定事件处理程序而另一个尝试解除绑定)

另一个更简单但维护性较差的解决方案是简单地将插件编辑为类似于(function($)...)(jQuery142) 而不是(function($)...)(jQuery)

【讨论】:

我尝试了您的解决方案,它有效。很快,我将发布我如何做到这一点的详细信息。我想我会给你赏金,除非接下来几天有更好的事情出现。【参考方案2】:

版本

有一个脚本专门尝试解决此问题:Versions。不过,它已经相当老了。

它只是做版本切换的好帮手。

虽然我自己没有测试过这个脚本,但你可以根据项目的 GitHub 存储库做这样的事情:

<!-- Old jQuery and it's plugins -->
<script type="text/javascript" src="../jquery/jquery-1.2.6.js"></script>
<script type="text/javascript" src="test-plugin-for-old.js"></script>

<!-- Include the Versions helper -->
<script type="text/javascript" src="versions.js"></script>

<!-- Include a new jQuery -->
<script type="text/javascript" src="../jquery/jquery.js"></script>
<script type="text/javascript">
Versions.add('jquery', 'latest', jQuery.noConflict(true));
Versions.add('jquery', 'default', jQuery);
</script>

<!-- Load a plugin into the new jQuery -->
<script type="text/javascript">jQuery = Versions.use('jquery', 'latest');</script>
<!-- Do whatever you need with the new jQuery -->
<script type="text/javascript" src="test-plugin-for-new.js"></script>
<!-- Finish up and use the old jQuery back -->
<script type="text/javascript">jQuery = Versions.use('jquery', 'default');</script>

按需 JavaScript 加载(延迟加载)

除此之外,还有some ways to do on-demand JavaScript loading,但我认为它们不能很好地加载 jQuery,因为 jQuery 修改并需要存在 window 对象。

另外,您可能想了解脚本加载。在this *** question 和article pointed out 中有更多详细信息。

RequireJS

列表中没有提到RequireJS。它相当新,您可以执行以下操作:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html><head>
  <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"></script>
  <script type="text/javascript" src="pageStuff.js"></script>
</head>
<body>
Welcome to our page.
<div id="app">
    <script type="text/javascript" src="require.js"></script>
    <script type="text/javascript">
      require(context: "1.4.2", 
        ["http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"],
        function() 
          console.log($.fn.jquery); // returns 1.4.2
          // myStuff.js
        );
      require(context: "1.2.6", 
        ["http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"],
        function() 
          console.log($.fn.jquery); // returns 1.2.6
        );
    </script>
</div>
</body></html>

我总是喜欢最新的东西,哈哈,所以我推荐这个。但是,由于加载 jquery 的性质(它修改了上面提到的window),所有对$jQuery 的引用在上面的HTML 代码块中的最后一个require 之外,都将引用jQuery 1.2.6.

【讨论】:

我不确定我是否要试试这个,但它看起来会奏效。 试用 RequireJS 非常简单。我建议先尝试一下。 :)【参考方案3】:
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" />
<script type="text/javascript">
    $new = $.noConflict();

    document.write("$new = " + $new.fn.jquery + "<br/>");
    document.write("$ = " + $.fn.jquery + "<br/>");

</script>

我刚试过这个,它似乎工作,$ 报告是旧版本,你只需要确保在调用 jquery 时使用 $new 来处理你想用 1.4.2 做的事情

【讨论】:

我知道这件事。我只是希望我可以使用新版本的 jQuery,而无需向全局命名空间添加新变量。我不知道托管我的应用程序的页面上的代码是否会更改,并出于某种目的使用名称 $new(或我选择的任何名称)。另外,如果我试图在外部文件中包含插件怎么办?我是否需要将所有出现的 $ 和 jQuery 更改为 $new?我试图避免这样做。我不喜欢更改复杂插件的来源。另外,如果插件在其他服务器上,我不能直接修改源怎么办?【参考方案4】:

jQuery 实际上是window 上下文中的变量。因此,每当您加载 jQuery 库时,如果您在任何函数之外加载它,它将在 window 上下文中创建该变量。

相信你可以做这样的事情来实现你想要的。虽然有些限制,但理论上它应该可以工作:

<script type="text/javascript">
  // Get new jQuery code
  $.get( "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js", function (data, textStatus, XMLHttpRequest)
    if(data)
      // data should contain the file content. eval() it
      eval(data);

      // Use jQuery 1.4.2 from here, only inside this callback function.
    
  , "html" );
</script>

丑陋的,但应该可以解决问题。

【讨论】:

我试过了,但没有用。我放入回调函数中的任何内容都不会执行。我不知道 jQuery 1.2.6 中是否存在 $.get 函数。我可能会尝试找出答案,或者我可能会尝试其他方法。 $.get 从 1.0 开始存在。尝试将alert(1) 放入回调函数中,然后查看它是否执行。如果不是,那么您的语法可能有问题。 我试过这个: 并且没有执行任何警报语句. $.get 确实存在于 1.2.6 上。只需创建一个包含 1.2.6 的纯 HTML 文件并执行以下操作:alert($.get)。你应该得到功能代码。如果你不这样做,那么其他地方就有问题。【参考方案5】:

目前,我将支持 Tgr 的解决方案。以下是我如何实现它的详细信息:

page.html:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
    "http://www.w3.org/TR/html4/loose.dtd">
<html><head>
<script type="text/javascript" src="jquery-1.2.6.min.js>
<script type="text/javascript" src="pageStuff.js"></script>
</head>
<body>
Welcome to our page.
<div id="app">
    Here is our app.
    <script type="text/javascript">
        var oldJQuery = $;
    </script>
    <script type="text/javascript"
        src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
    <script type="text/javascript" src="myStuff.js"></script>
</div>
</body></html>

myStuff.js:

var jq142 = jQuery.noConflict(true);
(function($) 
    var jQuery = $;
    $(function() 
        //init app stuff
        includeScript("jCarousel.js", function() 
            //init carousel stuff
        );
    );
)(jq142);

function includeScript(URL, callback) 
    window.$ = window.jQuery = jq142;
    window.$.ajax(
        url: URL,
        dataType: "script",
        error: function() 
            window.$ = window.jQuery = oldJQuery;
        ,
        success: function() 
            if (typeof callback != "undefined")
                callback();
            window.$ = window.jQuery = oldJQuery;
        ,
        async: false
    );

我仍然不喜欢将另一个变量 (jq142) 放入全局命名空间的想法,但我想不出任何合理的解决方法。如果我想出更好的东西,我会在这里发布。

【讨论】:

以上是关于使用 getScript 在页面上使用多个版本的 jQuery 导入插件的主要内容,如果未能解决你的问题,请参考以下文章

Bootstrap 4如何在同一页面上使用多个jQuery版本[重复]

同一页面上的多个版本的脚本 (d3.js)

getScript 创建 ReferenceError

脚本完全加载并执行时,jquery .getscript()回调

jquery怎么刷新页面

[转]jquery刷新页面(局部及全页面刷新)