Dojo AMD:无法在 require 内部调用函数

13

我是一个Dojo的新手,但当我开始使用Dojo 1.7.2版本来开发新应用程序时,我也想使用新的AMD语法来编写函数。不幸的是,我好像无法理解它 :-(

最让我烦恼的是,我不能简单地调用任何在"require"块内部的函数。例如,我有一个页面,在打开时创建一个带有多个小部件的动态表格。然后我有一个按钮,每次按下时都会添加一行空白行。

如果没有AMD语法,那就很容易:
- 将所有的“dojo.require()”放在HEAD中
- 然后创建一堆自己的函数来创建表格和小部件
- 添加行函数可以轻松访问任何先前函数填充的全局变量

但是在AMD中就像这样:

初始函数创建表格和小部件:

function fillReportTable(repId) {
require(["dojo/dom-construct", "dojo/dom-attr", "dijit/form/FilteringSelect",
"dojo/data/ItemFileReadStore", "dijit/form/ComboBox", "dijit/form/DateTextBox", "dijit/form/Select", "dojo/store/Memory"],
     function (domConstruct, domAttr, FilteringSelect, ItemFileReadStore, ComboBox, DateTextBox, Select, Memory) {
   // a lot of code to create the table, consisting of SEVERAL functions 
   function createNewRow(tbl) { ...} 
   function function1 () {... } 
   function function2 () {... } 
   function function3 () {... } 
}

现在,“添加空行”按钮调用了自己的函数“addEmptyRow”。
但是,在这个函数中,我必须:
- 再次为每个dojo模块执行另一个require
- 我不能使用任何在“fillReportTable”函数“内部”的函数。例如,“createNewRow”函数

 function addEmptyRow() {
require(["dojo/dom-construct", "dojo/dom-attr", "dijit/form/FilteringSelect",
"dojo/data/ItemFileReadStore", "dijit/form/ComboBox", "dijit/form/DateTextBox", "dijit/form/Select", "dojo/store/Memory"],
     function (domConstruct, domAttr, FilteringSelect, ItemFileReadStore, ComboBox, DateTextBox, Select, Memory) {
// a lot of code to create the table, consisting of SEVERAL functions
}

AMD 看起来似乎非常复杂。
或者我在这里漏掉了什么明显的东西?
使用 AMD,如果您将代码分解为许多小函数,您是否需要在每个函数内部再次进行“require”?还是将所有函数都放在一个具有完整列表的“require”中?
如果采用第二种方式,如何从小部件事件中调用这些函数?

3个回答

11

最简单的方法是定义你自己的模块。首先查看这个教程:

http://dojotoolkit.org/documentation/tutorials/1.7/modules/

现在定义你自己的模块,例如"./js/mymodules/mymodule.js"(相对于HTML页面):

define([
    "dojo/dom-construct",
    "dojo/dom-attr",
    "dijit/form/FilteringSelect",
    "dojo/data/ItemFileReadStore",
    "dijit/form/ComboBox",
    "dijit/form/DateTextBox",
    "dijit/form/Select",
    "dojo/store/Memory"
], function (domConstruct, domAttr, FilteringSelect, ItemFileReadStore, ComboBox, DateTextBox, Select, Memory) {

    function fillReportTable(repId) {
       // a lot of code to create the table, consisting of SEVERAL functions 
       function createNewRow(tbl) { ...} 
       function function1 () {... } 
       function function2 () {... } 
       function function3 () {... } 
    }

    function addEmptyRow() {
       // a lot of code to create the table, consisting of SEVERAL functions
    }

    // Return an object that exposes two functions
    return {
        fillReportTable: fillReportTable,
        addEmptyRow: addEmptyRow
    }

});

并且像这样使用您的模块:

<html>

<head>

<script>
var dojoConfig = {
    baseUrl: "./js/",
    packages: [
        { name: "dojo", location: "lib/dojo" },
        { name: "dijit", location: "lib/dijit" },
        { name: "dojox", location: "lib/dojox" }
    ]
};
</script>

<script data-dojo-config="async: true" src="js/lib/dojo/dojo.js"></script>

</head>

...

<script>
require([
    "mymodules/mymodule"
], function (mymodule) {
    mymodule.fillReportTable(...);
    mymodule.addEmptyRow(...);
});
</script>

那么,返回对象中的 fillReportTable: fillReportTable 会暴露 fillReportTable() 函数吗? - joakimdahlstrom
是的,没错。当mymodule模块被require时, AMD加载器将加载该模块的特定JS文件(在我们的情况下是“mymodules/mymodule.js”). 在那个JS文件中,您要将一个函数传递给define,并且这个函数被用于"导出"该模块的功能性。在你的情况下,该模块代表了一个具有两个辅助函数的对象。 - Paul Grime
那么现在我可以从 require 之外的任何地方调用 mymodule.fillReportTable() 吗? - Andy N
在上述请求中设置对象dojo.setObject('fillReportTable',mymodule.fillReportTable)。然后在请求之外执行getObject。 var fillReportTable = dojo.getObject('fillReportTable'); 现在fillReportTable()在全局空间中。 - Andy N

4

试试这个:

require([...], function() {
    var myFunctions = dojo.getObject('myFunctions', true);
    myFunctions.createNewRow = function(...) {
        ...
    };
});

现在,您可以通过使用

函数名称()

从任何地方调用您的函数。

myFunctions.createNewRow();

如果你不想使用'myFunctions',你可以这样做:
require([...], function() {
    var createNewRow = function(...) {};

    dojo.setObject('createNewRow', createNewRow);
});

3

Paul Grime给出了一个很好的例子,所以我想分享一些想法。

你不需要在每个函数中定义所有的模块,这样会浪费大量的空间。然而,即使你尝试多次加载一个模块,Dojo也只会加载一次。

下面是我最近项目中的一个简化版模块,其功能相当无意义:

//app module in 'my' folder

define(
[
    'app/elements',
    'dojo/query',
    'dojo/on',
    'dojo/fx',
    'dojo/_base/fx',
    'dojo/dom-construct',
    'dojo/_base/event'

    //and so on.....
], 

function(elements, q, on, fx, baseFx, constr, event)
{   
    return {

        init : function()
        {
            var node = q(elements.loading);
            this.removeNode(node);

            this.addEvents();
        },

        removeNode : function(node)
        {
            node.remove();
        },

        addEvents : function()
        {
            $(elements.buttons).on('click', function(e)
            {
                alert(q(e).attr('id') + ' was clicked!');
            });
        }   
    }
}

我用以下方法获取模块

define(
[
    'my/app',
], 

function (app) 
{
    app.init();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接