【问题标题】:Transparently load and use jQuery in a widget with no conflicts在没有冲突的小部件中透明地加载和使用 jQuery
【发布时间】:2020-12-16 11:01:28
【问题描述】:

前提:我需要制作一个透明可重用的小部件,它使用 jQuery 并且可以在任何页面上工作(即使页面加载并使用它自己的 jQuery 版本);小部件将通过托管页面上的单个 <script="widget.js"> 标签加载。

我知道 noConflict() 建议的解决方案,例如 https://stackoverflow.com/a/528251/1710180

我有两个担心:

  1. 由于小部件本身是通过 JS 标签加载的,因此它将插入到文档中以加载 jQuery 库的任何 <script src="jquery.js"> 标签都将异步加载(AFAIK 即使使用 document.write());因此,两步 noConflict() 分辨率充其量是不可靠的。
  2. 小部件还需要加载各种 jQuery 插件;一旦 jQuery 可以在不与 jQuery_widget 全局冲突的情况下解决,我怎么能让这些插件绑定到 jQuery_widget 而不是 jQuery

我能想到的最佳解决方案是使用 ES6 处理器编译和打包整个混乱;这至少可以解决我在全局命名空间中的 jQuery 名称冲突;但是,我将使用的一些插件不是 ES6 就绪的,所以第 2 点)仍然不会被这个解决方案解决,因为它们不会使用 ES6 导入。

想到的另一个肮脏的解决方案是将所有内容加载到 iframe 中并使用iframe.contentWindow.$ 来操作主机窗口;我不知道jQuery的跨框架有多可靠,我从来没有尝试过这样的东西。

【问题讨论】:

    标签: javascript jquery ecmascript-6


    【解决方案1】:

    您至少有两个选择:

    1. 执行您所描述的操作,这将涉及您的小部件将script 标记输出到目标页面,触发浏览器无法预测的每个资源(jQuery、插件、您的代码)的 HTTP 请求,因此无法预取。这对性能不利。

    2. 打包代码。

    让我们按顺序来。

    做你描述的事情

    ...小部件将通过托管页面上的单个 <script="widget.js"> 标签加载。

    这部分对这项工作至关重要。如果有人使用deferasync,它将不起作用。由于加载时间的影响,我建议您的小部件的用户将该脚本标记放在他们文档的最后,就在关闭 </body> 标记之前。

    使用document.write,让您的widget.js 按此顺序输出您的脚本:

    1. 您的 jQuery 副本。这将暂时接管 $jQuery 全局标识符。
    2. 您需要的所有 jQuery 插件。这些将通过 jQuery 全局(如果它们编写正确)向 jQuery 注册。
    3. 包含您的主要代码的脚本,以(在范围函数内)开头:
      (function() {
          const $ = jQuery.noConflict(true);
          // ...the main body of your code here...
      })();
      
      ...这会将$jQuery 全局变量返回到它们在步骤#1 之前的状态,并在该范围函数中为您提供$ local 以在您的代码中使用。

    打包代码

    但是,您可能可以避免这种情况。捆绑器早在 ES2015 之前就已经存在,但即使你找不到,你也可以自己做:实际上只是按照上面给出的顺序连接你的各种脚本,在它们之间加上一个 ;,形成一个单一的 widget.js 文件并通过任何体面的缩小器运行它。由于上述原因,这将使页面上任何预加载的 jQuery 不受影响,同时只需要一个 HTTP 请求。它还允许您的用户使用asyncdefer,因为您的脚本不必使用document.write.

    【讨论】:

    • 谢谢,你确定document.write 会同步加载<script> 标签吗?我记得我的结果好坏参半;如果它异步加载 JS,那么在覆盖 jQuery、加载插件和运行无冲突代码之间将有一段时间,当可能发生主机事件时会发现 $/jQuery 处于不确定状态...
    • 对于 ES6 处理器,我自己也有过这样的想法,但是有些插件不是 ES6 就绪的......但是按照你的建议制作我自己的自定义打包器可能会成功,即将到来想一想……只是将所有东西都包装在一种人为的全局 ns 闭包中。看起来很有希望。
    • @Dinu - “谢谢,你肯定 document.write 会普遍同步加载 是的,完全确定。 “对于 ES6 处理器,我自己也有过这样的想法,但是有些插件还没有支持 ES6。” 对——这就是为什么我指出早在 ES2015(ES6 ),我希望你仍然可以找到一个积极维护的。 (据我所知,Webpack 或 Rollup 支持一些 ES5 级别的东西;我还没有研究过。)
    • @Dinu - "...只是将所有内容包装在一种人工的全局 ns 闭包中..." 只有 您的 代码,而不是 jQuery或小部件。 jQuery 不是以这种方式包装的,小部件可能是也可能不是。
    • (实际上,我已经很多年没有看 jQuery 了,将其封装在一个作用域函数中可能还可以。但没有任何理由给出noConflict(true)。)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-01
    相关资源
    最近更新 更多