9

我正在使用requirejs + jquery + jqueryui。我已经阅读了大量有关如何执行此操作的示例。我想我了解各种方法,在我看来我的设置应该可以正常工作。但是,我偶尔会在依赖 jquery-ui 的自定义模块中收到$.widget is not defined错误。这很痛苦,因为它不一致且难以重现,因此我很难测试替代方法。

我没有填充我所有的 jquery 插件,因为有很多。相反,我使用单独的 requirejs 调用加载 jquery。然后,在回调中,我加载了其余的东西。这样我就不必为我的所有 jquery 插件维护一个垫片列表。

对于 jquery-ui,我使用 shim 使其依赖于 jquery。然后我所有使用小部件工厂的自定义模块在其依赖项列表中都有'jquery-ui'。

在我的模板中...

requirejs.config({
    baseUrl: ATHLETE.siteConfig.jsBaseUrl,
    paths: {
        'jquery': '//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min',
        'jquery-ui': '//ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min'
    },
    shim: {
        "jquery-ui": ['jquery']
    },
    waitSeconds: 15
});

requirejs(['jquery'], function($) {
    requirejs(['site'], function() {
        requirejs(['mypage']);
    });
});

请注意,我在 mypage.js 之前加载 site.js。他们有一些共享的依赖关系。在我的构建配置中,我从 mypage.js 中排除了 site.js,因此共享依赖项被编译到 site.js 而不是 mypage.js。因此,我需要在加载 mypage.js 之前完全加载 site.js,否则 require 可能会尝试单独加载这些共享依赖项。

这是我的一个示例自定义模块,它依赖于 jquery-ui。

define([
    'jquery',
    'jquery-ui'
],function($) {
    $.widget('ui.viewAllSponsorsWidget', $.ui.dialog, {
        options: {
            autoOpen: false,
            dialogClass: 'view-all-sponsor-dialog-wrap',
            draggable: false,
            modal: true,
            resizable: false,
            width: 370,
            height: 400
        }
    });
});

错误 $.widget is not defined 是由这个和我的类似自定义模块的第 5 行引起的。同样,它确实不一致且难以重现。通常情况下,即使我清除了缓存,我也不会收到错误消息。谁能想到在 jquery-ui 完全加载之前执行第 5 行的方法?

2013 年 8 月 16 日更新

我已经能够更多地追踪这一点。我创建了一个依赖于 jquery 和 jquery-ui 的简单模块。

define([
    'jquery',
    'jquery-ui'
],function($) {
    console.log('$.widget is defined? ' + Boolean($.widget));
    console.log('jQuery.widget is defined? ' + Boolean(jQuery.widget));
});

其输出如下:

LOG: $.widget is defined? false
LOG: jQuery.widget is defined? true

所以不知何故,全局 jQuery 对象定义了小部件,但 requirejs 提供给我的副本没有。

4

7 回答 7

3

将您的垫片更改为:

shim: {
    'jquery-ui': ['jquery']
}

下面是一些流行库的 Require.js 配置示例。

于 2013-08-01T19:37:46.860 回答
3

有一个类似的问题是第 3 部分 ASP.NET 控件正在劫持 jQuery 定义。

$telerik.$ = jQuery.noConflict();

虽然脚本自己清理了,但 jQuery 脚本的尾部有效地覆盖了我的 RequireJS 映射

if ( typeof define === "function" && define.amd ) { define( "jquery", [], function () { return jQuery; } ); }

RequireJS 会延迟加载脚本,而 RadScriptManager 会继续在表单标签下注入脚本,因此会出现一些奇怪的竞争问题。

对于某些请求,$ 来自我的地图并且是全局的其他请求 $ 是 $Telerik.$ 并且不是全局的并且是不同的版本

为了解决我的问题,我回滚到 Telerik 控件正在使用的 jQuery 版本,并将其硬编码在一个脚本标签中,以确保它始终可用,然后禁用 Telerik 加载自己的 JQuery。不是 AMD,但对我来说足够好。

于 2013-12-06T20:28:12.940 回答
3

这些答案有点老了。我希望提供一点更新的答案。jQuery UI 现在内置了 AMD 支持。你可以简单地使用它

bower install jquery-ui

然后在 requirejs.config 中只需将 jquery_ui 添加到 paths{} 部分。不再需要垫片。

如果你只想加载你需要的 jquery-ui 的一小部分,那么 bower install jquery-ui 然后使用 requirejs 提供的构建工具来创建一个包。否则,如果你只尝试导入一个单独的文件,那么每个 jquery-ui 文件都会尝试加载它们的依赖项,你会得到“widget not defined”或“cannot find file widget.js”等信息。我做了一个快速写在这里: https ://hendrixski.wordpress.com/2015/04/17/adding-only-the-parts-of-jquery-ui-that-you-need-into-your-requirejs-project/

希望有帮助。

于 2015-04-17T18:46:38.083 回答
0

我想我有办法解决我的问题。虽然由于这个问题很难重现,但我要等一段时间才能“接受”我自己的答案是正确的。另外,我的回答没有使用 requirejs 加载 jquery。我不明白为什么这对我很重要。但是,如果有人看到无需在单独的脚本标签中加载 jquery 即可完成此操作的方法,请告诉我。

由于 jQuery 将自己定义为一个命名的 AMD 模块,因此我可以在执行任何 requirejs 操作之前先使用标准脚本标记简单地同步加载它。然后我还删除了 jquery 的路径条目,因为此时它已经以名称“jquery”加载。通过这样做,requirejs 会向我返回正确的 jQuery“副本”,并且一切正常。我还需要使用 jQuery.noConflict,因为我使用依赖于 Prototype 的 Garmin Communicator。所以,这是我更新的代码,省略了不相关的部分。

<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript">$.noConflict();</script>
<script type="text/javascript">
requirejs.config({
    baseUrl: ATHLETE.siteConfig.jsBaseUrl,
    paths: {
        'jquery-ui': '//ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min'
    },
    shim: {
        "jquery-ui": ['jquery']
    },
    waitSeconds: 15
});
requirejs(['mymodule']);
</script>

而且我的模块仍然可以像往常一样依赖 jquery 和 jquery-ui:

define([
    'jquery',
    'jquery-ui'
],function($) {
    $.widget('ui.mycoolwidget', ...);
});
于 2013-08-16T20:46:08.617 回答
0

如果你想覆盖 jQuery-ui 的某些方法,那么最好使用 Requirejs init 方法,这样可以确保在每个包含 jQuery-ui 的模块中使用相同的修改代码。

像这样使用你的垫片

  'jquery-ui': { deps: ['jQuery'], init: function ($) {

  //do whatever with $.widget , all reference of 
  // jQuery-ui is accessible here, override 


 return this;   //very imp , so all your module will use your 
                // modified jQuery-UI reference

 } },
于 2013-12-26T13:39:37.267 回答
0

在将 jQuery UI 与 Require.js 一起使用时,我遇到了一个类似的、非常偶然的错误,我通过使用 jqueryui -amd转换脚本创建“用于 jQuery UI 的 AMD 包装模块以在 RequireJS 等加载器中使用”来修复该错误。

  1. 使用 npm 安装。

    npm install -g jqueryui-amd
    
  2. 转换从 jqueryui.com 下载的 jQuery UI JavaScript 文件

    jqueryui-amd path/to/jquery-ui-version
    
  3. 然后将新转换jqueryui目录的路径添加到您的 require.js 配置文件中。

    requirejs.config({
        paths: {
            jqueryui: 'path/to/jquery-ui-version/jqueryui'
        }
    });
    
  4. 最后,在您使用 jQuery UI 组件之一的 JavaScript 文件中。

    define(['jquery', 'jqueryui/widget', 'jqueryui/button'], function ($) {
        //Use widget and button in here, off of the given $ variable.
    });
    
于 2014-02-25T10:21:02.667 回答
0

我遇到了和你一样的问题,在 RequireJS 模块中定义我的小部件,尽管我不是 100% 确定这是最好的解决方案,但它对我来说是一个在不违反模块完整性的情况下工作的解决方案:

requirejs.config({
     //By default load any module IDs from js/lib
        baseUrl: 'js',
        shim: {
            'jquery': {
                exports: 'jQuery'
            },
            'jquery-ui': {
                deps: ['jquery'],
                exports: '$'
            }
        }
  });

当您在模块中需要 jquery-ui 时,将自动需要 jQuery,并且 $ 对象将拥有您需要的一切。

于 2014-05-30T04:16:49.743 回答