requirejs + jqueryui = $ .widget未定义

时间:2013-07-22 17:02:40

标签: jquery-ui requirejs amd jquery-ui-widget-factory

我正在使用requirejs + jquery + jqueryui。我已经阅读了很多关于如何做到这一点的例子。我想我了解各种方法,在我看来,我的设置应该正常工作。但是,我偶尔在依赖于jquery-ui的自定义模块中得到 $。小部件未定义错误。这是一种痛苦,因为它不一致且难以复制,因此我很难测试其他方法。

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

对于jquery-ui,我使用垫片使其依赖于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未定义是由我和此类似自定义模块的第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对象定义了widget,但requirejs提供给我的副本却没有。

7 个答案:

答案 0 :(得分:3)

将你的垫片更改为:

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

这是流行库的一堆Require.js配置的example

答案 1 :(得分: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,但对我来说效果还不错。

答案 2 :(得分:3)

这些答案有点老了。我希望提供一些更新的答案。 jQuery UI现在内置了AMD支持。您只需使用

即可获得它
bower install jquery-ui

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

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

希望有所帮助。

答案 3 :(得分: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', ...);
});

答案 4 :(得分: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

 } },

答案 5 :(得分:0)

我在使用带有Require.js的jQuery UI时遇到类似的,非常偶然的错误,我使用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.
    });
    

答案 6 :(得分: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将是自动需要的,而$ object将拥有你需要的一切。