如何将依赖于 jQuery 的 Javascript 小部件嵌入到未知环境中

IT技术 javascript jquery widget
2021-03-04 22:26:36

我正在开发一个依赖于 jQuery 的 javascript 小部件。小部件可能会也可能不会加载到已经加载了 jQuery 的页面上。在这种情况下会出现很多问题......

  1. 如果网页没有 jQuery,我必须加载我自己的 jQuery。然而,这样做时似乎存在一个微妙的时间问题。例如,如果我的小部件在 jQuery 完成加载和执行之前加载和执行,我会收到jQuery is not defined错误消息。

  2. 如果网页确实有 jQuery,我通常可以使用它。但是,如果 jQuery 版本较旧,我想加载我自己的版本。但是,如果我确实加载了自己的内容,则需要以不踩踏$变量的方式进行加载如果我设置了jQuery.noConflict()并且他们的任何脚本依赖于$,那么我刚刚破坏了他们的页面。

  3. 如果网页使用另一个 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);

如果有任何指针或资源来实现可以在所有提到的环境中工作的小部件,他们将不胜感激。

6个回答

在查看了一些答案和提示,并找到了一些有用的 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 传递给它。

这是我改编的咖啡脚本版本:gist.github.com/4361800感谢您提供出色的解决方案!顺便说一句,题外话,但我真的不明白(window, document, "1.3", function($, jquery_loaded) {它在函数末尾的语法。我在哪里可以阅读更多相关信息?
2021-04-26 22:26:36
没有比这更好的了,希望我能多给分!
2021-05-01 22:26:36
HIERARCHY_REQUEST_ERR: DOM Exception 3当它在格式错误的 html(文件顶部的空白行)上运行时,看到了一个错误。更换document.documentElement.childNodes[0].appendChild(script)(document.getElementsByTagName("head")[0] || document.documentElement).appendChild(script_tag);从下面似乎更好地工作。
2021-05-04 22:26:36
不幸的是,我认为您的字符串版本比较不适用于 1.10 及更高版本。
2021-05-13 22:26:36
我做过与此非常相似的事情。如果您能帮助解决此问题,我将不胜感激stackoverflow.com/questions/7817522/...
2021-05-15 22:26:36

请参阅Alex Marandon 的如何构建 Web 小部件(使用 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

如果您还想使用一些 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
});
我正在尝试做一些与此非常相似的事情。你能帮我解决这个问题吗?stackoverflow.com/questions/7817522/...
2021-05-16 22:26:36

您可以使用 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);
 }
})()
我实际上最终得到了一些非常相似的东西,我将尝试将其作为另一个答案发布(因为我仅限于评论中的字符数)。
2021-04-18 22:26:36