gpt4 book ai didi

javascript - RequireJS 影响嵌入式 jquery-ui 小部件

转载 作者:搜寻专家 更新时间:2023-11-01 04:35:06 25 4
gpt4 key购买 nike

我有一个合作伙伴正在尝试嵌入的 jQuery 小部件。我们遇到的问题是合作伙伴正在使用 requireJS 及其影响小部件。

该小部件位于匿名函数中,并且需要在其中使用 jquery-ui。调试后我们发现 jQuery UI 在 noConflict 调用后被删除。这是来自小部件的代码。

(function () {

// Localize jQuery variable
var jQueryWidget;

/******** Load jQuery if not present *********/
if (window.jQuery === undefined || window.jQuery.fn.jquery !== '3.2.1') {
var script_tag = document.createElement('script');
script_tag.setAttribute("type", "text/javascript");
script_tag.setAttribute("src", "https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js");
script_tag.onload = scriptLoadHandler;
script_tag.onreadystatechange = function () { // Same thing but for IE
if (this.readyState == 'complete' || this.readyState == 'loaded') {
scriptLoadHandler();
}
};
(document.getElementsByTagName("head")[0] || document.documentElement).appendChild(script_tag);
} else {
loadJQueryUi();
}

function scriptLoadHandler() {
loadJQueryUi();
}

function loadJQueryUi() {
/******* Load UI *******/
jQuery.getScript('https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js', function () {
jQueryWidget = jQuery.noConflict(true);
setHandlers(jQueryWidget);
});


/******* Load UI CSS *******/
var css_link = jQuery("<link>", {
rel: "stylesheet",
type: "text/css",
href: "https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/base/jquery-ui.css"
});
css_link.appendTo('head');
}

function setHandlers($) {
$(document).on('focus', '#start-date, #end-date', function(){

$('#start-date').datepicker({
dateFormat: "M dd, yy",
minDate: 'D',
numberOfMonths: 1,
});

$('#end-date').datepicker({
dateFormat: "M dd, yy",
minDate:'+1D',
numberOfMonths:1,
});
}
})();

使用 chrome 调试器我们可以看到,当 getScript 被调用时,它正确地将 jquery-ui 添加到加载的版本中。在我们调用 noConflict 之后,它直接恢复了以前的 jQuery 但版本不再具有 jQueryUI。

在没有 requireJS 的情况下在其他站点上测试小部件可以正常工作。

有没有人遇到过这个?不幸的是,我们之前没有使用过 RequireJS,但不明白为什么它会影响匿名函数。

任何帮助将非常感激。

最佳答案

问题是你试图做的事情是不安全的。有两个因素综合起来对您不利:

  • 脚本是异步加载的。您唯一可以控制的是您的小部件加载 jQuery 和 jQueryUI 的相对顺序。但是,您的小部件运行所在的页面也会加载它自己的 jQuery 版本。 您的代码不能强制执行合作伙伴代码加载的脚本的加载顺序。
  • jQuery 不是一个表现良好的 AMD 模块。 一个行为良好的 AMD 模块调用 define获取其依赖项,并且不会将任何内容泄漏到全局空间中。不幸的是,jQuery 确实泄漏了 $jQuery进入全局空间。

  • 结合这两个因素,您将面临竞争条件,具体取决于两个版本的 jQuery 加载顺序:通常不可能知道全局符号是哪个版本的 jQuery $jQuery指的是。考虑你的代码:
    jQuery.getScript('https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js', function () {
    jQueryWidget = jQuery.noConflict(true);
    setHandlers(jQueryWidget);
    });

    你不知道是否 jQuery指您要求加载的版本或合作伙伴代码想要加载的版本。唯一 .getScript保证在脚本加载后将调用回调,但它确实 不是 防止其他脚本在 .getScript 的脚本之间加载加载和调用回调的时间。浏览器可以完全免费加载您提供给 .getScript 的脚本,加载一些通过 RequireJS 请求的其他脚本,然后调用您的回调。

    如果您希望您的小部件成为可以放入页面而无需更改任何现有代码的东西,那么没有简单的修复方法。您不能只更改您在问题中显示的逻辑,也不能只将 RequireJS 添加到您的小部件中。 RequireJS 本身不能解决这个问题。与其他答案所暗示的相反, context RequireJS 的配置选项不是修复。如果没有试图通过全局 $ 访问 jQuery 的脚本,这将是一个修复。或 jQuery ,但是有很多 jQuery 插件可以做到这一点。您无法确保合作伙伴代码不使用它们。

    并注意似乎可以解决问题的建议修复程序。您可以尝试修复,它似乎有效,并且您认为问题已解决,但实际上问题并未表现出来,因为这是一个竞争条件。一切都很好,直到一个月后,另一个合作伙伴加载您的小部件并繁荣起来:他们的页面创造了正确的条件,使事情按照搞砸了您的代码的顺序加载。

    还有一种额外的并发症,您可能还没有遇到,但肯定会不时发生。 (同样,您正在处理竞争条件,所以...)您的代码正在通过 script 加载 jQuery 和 jQuery UI。元素。然而,他们都检查是否 define可用,如果可用,他们将调用 define .这可能会导致各种问题,具体取决于一切发生的顺序,但一个可能的问题是,如果 RequireJS 在您的小部件加载之前存在,jQuery UI 将从 script 调用定义。元素,这将产生 mismatched anonymous define error . (jQuery 有一个不同的问题,它更复杂,不值得深入研究。)

    我可以看到让您的小部件在不受合作伙伴代码干扰的情况下加载的唯一方法,并且不需要合作伙伴更改他们的代码是使用类似 Webpack 的东西将您的代码构建到单个包中,其中 define应该强制在你的包中是假的,以便任何测试 define 存在的代码未触发。 (请参阅 import-loader ,它可以用于此目的。)如果您将代码作为单个包加载,那么它可以以同步方式初始化自己,并且您可以确定 $jQuery请参阅您的包中包含的 jQuery。

    如果您要遵循我的建议,这里有一个很好的示例,它充分利用了 Webpack,包括正确的缩小,并从您的代码中消除了这种方法不再需要的一些工件(例如 IIFE,以及一些您拥有的功能)。它可以通过保存文件在本地运行,运行:
  • npm install webpack jquery jquery-ui imports-loader lite-server
  • ./node_modules/.bin/webpack
  • ./node_modules/.bin/lite-server

  • 还有一些我第一次写解释时没有意识到的事情,但我现在注意到了。没有必要拨打 noConflict当你用 Webpack 包装你的代码时,因为当它被 Webpack 包装时,jQuery 检测到一个带有 DOM 的 CommonJS 环境并打开一个 noGlobal内部标志,防止泄漏到全局空间。
    webpack.conf.js :
    const webpack = require('webpack');
    module.exports = {
    entry: {
    main: "./widget.js",
    "main.min": "./widget.js",
    },
    module: {
    rules: [{
    test: /widget\.js$/,
    loader: "imports-loader?define=>false",
    }],
    },
    // Check the options for this and use what suits you best.
    devtool: "source-map",
    output: {
    path: __dirname + "/build",
    filename: "[name].js",
    sourceMapFilename: "[name].map.js",
    },
    plugins: [
    new webpack.optimize.UglifyJsPlugin({
    sourceMap: true,
    include: /\.min\.js$/,
    }),
    ],
    };

    您的小部件为 widget.js :
    var $ = require("jquery");
    require("jquery-ui/ui/widgets/datepicker");

    var css_link = $("<link>", {
    rel: "stylesheet",
    type: "text/css",
    href: "https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/base/jquery-ui.css"
    });
    css_link.appendTo("head");

    $(document).ready(function() {
    console.log("jQuery compare (we want this false)", $ === window.$);
    console.log("jQuery version in widget", $.fn.jquery);
    console.log("jQuery UI version in widget", $.ui.version);
    $("#end-date").datepicker();
    });
    index.html :
    <!DOCTYPE html>
    <html>
    <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.5/require.js"></script>
    <script>
    require.config({
    paths: {
    jquery: "https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.0/jquery.min",
    "jquery-ui": "https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.0/jquery-ui"
    }
    });
    require(["jquery", "jquery-ui"], function(myJQuery) {
    console.log("jQuery compare (we want this true)", myJQuery === $);
    console.log("jQuery version main", $.fn.jquery);
    console.log("jQuery ui version main", $.ui.version);
    })
    </script>
    </head>
    <body>
    <input id="end-date">
    <script src="build/main.min.js"></script>

    <!-- The following also works: -->
    <!--
    <script>
    require(["build/main.min.js"]);
    </script>
    -->
    </body>
    </html>

    关于javascript - RequireJS 影响嵌入式 jquery-ui 小部件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46810789/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com