简体   繁体   English

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

[英]using getScript to import plugin on page using multiple versions of jQuery

I am developing an app on a page that uses jQuery 1.2.6, but I would like to use jQuery 1.4.2 for my app. 我正在使用jQuery 1.2.6的页面上开发应用程序,但是我想为我的应用程序使用jQuery 1.4.2。 I really don't like to use multiple versions of jQuery like this but the copy on the page (1.2.6) is something I have no control over. 我真的不喜欢这样使用jQuery的多个版本,但是页面上的副本(1.2.6)是我无法控制的。 I decided to isolate my code like this: 我决定像这样隔离我的代码:

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

The file myStuff.js has my own code that is supposed to use jQuery 1.4.2, and it looks like this: 文件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));

This is an extremely simplified version, but I hope you get the idea of what I did. 这是一个非常简化的版本,但我希望您对我所做的有所了解。 For a while, everything worked fine. 有一阵子,一切正常。 However, I decided to use a jQuery plugin in a separate file. 但是,我决定在单独的文件中使用jQuery插件。 I tested it and it acted funny. 我对其进行了测试,它表现得很有趣。 After some experimentation, I found out that the plugin was using the old version of jQuery, when I wanted it to use the new version. 经过一些试验,当我希望该插件使用新版本时,我发现该插件正在使用旧版本的jQuery。 Does anyone know how to import and run a js file from the context within the function wrapping the code in myStuff.js? 有谁知道如何从包装myStuff.js中的代码的函数中的上下文中导入和运行js文件?

In case this matters to anyone, here is how I know the plugin is using the old version, and what I did to try to solve the problem: I made a file called test.js, consisting of this line: 万一这对任何人都重要,这就是我如何知道插件使用的是旧版本,以及我为解决该问题所做的工作:我制作了一个名为test.js的文件,其中包括以下内容:

alert($.fn.jquery);

I tried referencing the file in a script tag the way external Javascript is usually included, below myStuff.js, and it came up as 1.2.6, like I expected. 我尝试以通常包含外部Java脚本的方式在脚本标签中引用该文件,该文件通常位于myStuff.js下,并且像我期望的那样以1.2.6出现。 I then got rid of that script tag and put this line in myStuff.js: 然后,我删除了该脚本标记,并将此行放入myStuff.js中:

$.getScript("test.js");

and it still came back as 1.2.6. 仍然回到1.2.6。 That wasn't a big surprise -- according to jQuery's documentation , scripts included that way are executed in the global context. 这并不令人感到意外-根据jQuery的文档 ,以这种方式包含的脚本在全局上下文中执行。 I then tried doing this instead: 然后,我尝试这样做:

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

and it still came back as 1.2.6. 仍然回到1.2.6。 After some tinkering, I found out that the "this" keyword referred to the window, which I assume means the global context. 经过一番修补,我发现“ this”关键字是指窗口的,我认为这意味着全局上下文。 I am looking for something to put in place of "this" to refer to the context of the enclosing function, or some other way to make the code in the file run from the enclosing function. 我正在寻找代替“ this”的内容来引用封闭函数的上下文,或者通过某种其他方式使文件中的代码从封闭函数运行。 I noticed that if I copy and paste the code, it works fine, but it is a big plugin that is used in many places, and I would prefer not to clutter up my file with their code. 我注意到,如果我复制并粘贴代码,则可以正常工作,但是它是一个在许多地方使用的大插件,因此,我不希望它们的代码使文件混乱。 I am out of ideas. 我没主意。 Does anyone else know how to do this? 还有其他人知道该怎么做吗?

When you load jQuery, all it does is to create a root jQuery object and set window.jQuery and window.$ to point to it. 加载jQuery时,所有window.jQuery就是创建一个jQuery根对象,并将window.jQuerywindow.$为指向它。 So you can simply load the old jQuery, copy window.jQuery to window.jQuery126 , load the new jQuery, copy window.jQuery to window.jQuery142 , and then change window.jQuery and window.$ whenever you want a plugin to use the other version. 因此,您可以简单地加载旧的jQuery,将window.jQuery复制到window.jQuery126 ,加载新的jQuery,将window.jQuery复制到window.jQuery142 ,然后在希望插件使用时更改window.jQuerywindow.$其他版本。

This is an ugly and unstable hack but it should work as long as 这是一个难看且不稳定的骇客,但只要

  1. all code written for the non-default version is encapsulated with (function($){...})($) (proper jQuery plugins should do this, and you can easily ensure it for your own code) 为非默认版本编写的所有代码都用(function($){...})($)封装(正确的jQuery插件应执行此操作,您可以轻松地确保使用自己的代码)
  2. scripts used with different jQuery versions don't mess with each other's stuff (such as one binding an event handler and the other trying to unbind it) 与不同jQuery版本一起使用的脚本不会互相干扰(例如,一个绑定一个事件处理程序,而另一个则试图取消绑定)

Another, simpler but less maintainable solution is to simply edit the plugin to look like (function($){...})(jQuery142) instead of (function($){...})(jQuery) 另一个更简单但更难以维护的解决方案是简单地将插件编辑为(function($){...})(jQuery142)而不是(function($){...})(jQuery)

Versions 版本

There is a script that specifically attempts to fix this problem: Versions . 有一个脚本专门尝试解决此问题: Versions It's rather old, though. 不过,它已经很旧了。

It's just a neat helper for doing the switching of versions. 它只是进行版本切换的好帮手。

While I have not tested this script myself, you can do something like this based on the GitHub repository for the project: 虽然我自己尚未测试此脚本,但是您可以基于该项目的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>

On-Demand JavaScript Loading (Lazy Loading) 按需JavaScript加载(延迟加载)

With that out of the way, there are some ways to do on-demand JavaScript loading , but I don't think they will work well with loading of jQuery since jQuery modifies and requires the presence of the window object. 顺便说一句,有一些方法可以执行按需JavaScript加载 ,但是我认为它们无法与jQuery加载一起很好地工作,因为jQuery进行了修改并且需要window对象的存在。

Also, you might want to read about script loading. 另外,您可能需要阅读有关脚本加载的信息。 There's more details about it in this StackOverflow question and the article pointed out . 这个StackOverflow问题中有更多有关此问题的详细信息,并指出了本文

RequireJS RequireJS

In the list, RequireJS is not mentioned. 在列表中,未提及RequireJS It's rather new and you can do things like: 它相当新,您可以执行以下操作:

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

I always go for the newest stuff, haha, so I'm recommending this. 我总是去买最新的东西,哈哈,所以我推荐这个。 However, due to the nature of loading the jquery (it modifies window as mentioned above), all references to $ and jQuery outside and beyond the last require in the HTML code block above, will refer to the jQuery 1.2.6. 但是,由于加载jquery的性质(如上所述,它会修改window ),在上述HTML代码块中的最后一个require之外的所有对$jQuery引用,都将参考jQuery 1.2.6。

jQuery is actually a variable in the window context. jQuery实际上是window上下文中的变量。 So whenever you load a jQuery library it will create that variable in the window context if you load it outside any function. 因此,每当您加载jQuery库时,如果将其加载到任何函数之外,它将在window上下文中创建该变量。

I believe you could do something like this to achieve what you want. 相信您可以做这样的事情来实现您想要的。 Although somewhat restrictive, theoretically it should work: 尽管有些限制,但从理论上讲它应该起作用:

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

This is ugly, but should do the trick. 丑陋的,但应该做的伎俩。

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

I just tried this and it seems to work, $ reports to be the old version and you just have to make sure to use $new when invoking jquery for the stuff you want to do with 1.4.2 我只是试过了,它似乎起作用了,$报告是旧版本,您只需要确保在对要使用1.4.2进行处理的东西调用jquery时使用$ new

For now, I am going along with Tgr's solution. 现在,我将继续使用Tgr的解决方案。 Here are the details of how I implemented it: 以下是我实施方式的详细信息:

page.html: 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: 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
    });
}

I still don't like the idea of putting another variable (jq142) into the global namespace, but I couldn't think of any reasonable way around it. 我仍然不喜欢将另一个变量(jq142)放入全局名称空间的想法,但是我想不出任何合理的解决方法。 If I come up with something better, I will post it here. 如果我提出更好的建议,请在此处发布。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM