了解道场 AMD 加载功能未定义

Posted

技术标签:

【中文标题】了解道场 AMD 加载功能未定义【英文标题】:understanding dojo AMD loading- functions are undefined 【发布时间】:2013-12-03 21:48:39 【问题描述】:

我一直在试图让某人向我解释 dojo AMD 加载的工作原理,并让一段简单的代码工作。我知道如果使用例如 CDN,则必须调用 dojo 库并加载您希望使用的所有模块。我尝试根据主页上的活动来实现其他 javascript 函数,但我总是会得到未定义的函数或与未定义的 dojo 控件相关的错误。似乎最初加载的所有模块都不适用于其余代码。任何有用的解释将不胜感激。

          <link rel="stylesheet" type=
        "text/css" href="http://ajax.googleapis.com/ajax/libs/dojo/1.8.4/dojo/resources
                           /dojo.css" />
          <link rel="stylesheet" type=
        "text/css" href="http://ajax.googleapis.com/ajax/libs/dojo/1.8.4/dijit/themes/
                           tundra/tundra.css" />
          <link rel="stylesheet" type=
        "text/css" href="http://ajax.googleapis.com/ajax/libs/dojo/1.8.4/dojox/mobile/themes/
                           iphone/iphone.css" />
         <title> DOJO </title>
         <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/dojo/1.8.4/
                   dojo/dojo.js" 
              data-dojo-config="async:true"></script> 

      <script type="text/javascript" src="Scripts/login.js"></script>
     <script type="text/javascript">
      require(["dojox/mobile/parser",
                "dojo/parser",
                "dojo/on",
                "dojo/request/xhr",
                "dijit/form/Form",
                "dojo/store/Observable",
                "dojo/store/Memory",
                "dijit/Toolbar",
                "dijit/Dialog",
                "dojo/io/script",
                "dojo/query",
                "dojo/_base/lang",
                "dijit/layout/ContentPane",
                "dojox/mobile/Button",
                "dojox/mobile/deviceTheme",
                "dojox/mobile/compat",
                "dojox/mobile/Heading",
                "dojox/mobile/TextBox",
                "dojox/mobile/Opener",
                "dijit/form/TextBox",
                "dijit/form/HorizontalSlider",
                "dijit/form/ValidationTextBox",
                "dijit/Calendar",
                "dojox/mobile/ScrollableView",
                "dojo/dom",
                "dojo/domReady!",
                "dojox/mobile"],

        function (dom, domReady ,mobile, ScrollableView, 
               parser, query, domClass, domStyle, on, event, xhr,Form,
             lang, Button, deviceTheme, compat, Heading) 
            dojox.mobile.parser.parse();
        );

</script> 

据我了解,我拥有上面代码的方式是我的界面将正确加载,并且 html 正文中的所有小部件都将显示并且工作正常。问题是我有一个从用户那里获取输入的表单,并且在按钮单击事件上调用一个处理 webrequests 的函数。我无法让它工作,这只是我放置此功能的位置的问题。我添加了一个简化版本:

我所做的是将该函数添加到脚本文件中,以将其与其余代码分开:

var dojoXhr;

function correctInput(div, td, msg) 
dojo.domStyle.set(div, 'display', '');
td.innerHTML = msg;


require(["dojo/_base/declare", "dojo/parser", "dojo/query", "dojo/dom-class", 
     "dojo/dom-style",   "dojo/on", 
     "dojo/_base/event",
     "dojo/request/xhr", "dijit/form/ValidationTextBox", "dojo/domReady!"], 
  function chklogin(declare, parser, query, dom-class, dom-style, 
      on, event, xhr,ValidationTextBox, domReady) 

   var lname = dijit.byId('login').get('value');
   var psswd = dijit.byId('password').get('value');
   var feedback = document.getElementById('feedback');
   var feedbackTD = dojo.query('td.feedback')[0];
   if (lname == '' || psswd == '') 
       correctInput(feedback, feedbackTD, 'Please enter a valid login!');
       dojo.domStyle.set(feedback, 'display', '');
       dojo.domStyle.set(document.getElementById('msgBodyOutter'), 'display', 'none');
       feedbackTD.innerHTML = "Please enter a valid login!";
       return;
   
   if (!(lname == 'login') || !(psswd == 'password')) 
       correctInput(feedback, feedbackTD, 'Please enter a valid login!');
       return;
   
   else 
       dojo.domStyle.set(feedback, 'display', '');
       dojo.domStyle.set(document.getElementById('msgBodyOutter'), 'display', 'none');
       feedbackTD.innerHTML = "THATS IT BRO!";
       return;
   


);

我在 dojo 论坛上得到了建议,将我的函数放在定义函数中,然后使用 require 来调用它。我不知道该怎么做。

【问题讨论】:

【参考方案1】:

似乎所有最初加载的模块都不可用 剩下的代码。

您正在使用CDN 加载dojo 工具包。当您使用 CDN 时,您需要定义模块包的位置。您需要编辑 dojoConfig 才能使代码正常工作。

请参阅这篇关于Using Custom Modules with a CDN 的文章。重要的部分是包对象。

<script data-dojo-config="async: 1, dojoBlankHtmlUrl: '/blank.html',
        packages: [ 
            name: 'custom',
            location: location.pathname.replace(/\/[^/]+$/, '') + '/js/custom'
         ]"
    src="//ajax.googleapis.com/ajax/libs/dojo/1.9.1/dojo/dojo.js">
</script>

编辑: 下面是一个简单的 dojo 应用程序。

所以在我的例子中,创建一个名为 chklogin 的模块,然后 require 它,然后 当用户单击按钮时,它将调用该模块 chklogin 在主 require[] 函数中。对吗?

我会说是的。你是对的。我认为你的概念是一个可行的选择。我希望这个例子有助于实现 define() 来创建你自己的模块。当你发展你的想法时,我会尽我所能提供帮助。如果有空,您可以在此处download the project

目录结构:

/index.html
/js/config.js
/js/controller/Controller.js
/js/modules/MyFirstModule.js

/index.html

<!doctype html>
<html>
    <head>
    <meta charset="UTF-8">
     <title>Demo</title>
    <link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/dojo/1.9.1/dijit/themes/claro/claro.css">
    <script src="js/config.js"></script>
    <script src="http://ajax.googleapis.com/ajax/libs/dojo/1.9.1/dojo/dojo.js"></script>
    <script>
        require(["app/Controller", "dojo/domReady!"], function(Controller) 

            //Initiate the entire application by calling main method of our Controller class. 
            Controller.main();

            //Call our getter method of the Controller class to show how to access a private variable.
            console.log(Controller.getWelcomeMessage());
        );
    </script>
    </head>

    <body class="claro" id="appBody"></body>
</html>

/js/config.js

我们使用 packages 来引用 CDN dojo 文件。现在我们可以通过我们的包名来调用 dojo 类 例如,"dojo/domReady!""dijit/form/Button""dojox/app/main"。道场文件 存储在谷歌服务器上,由 &lt;script src='http://ajax.googleapis.com/ajax/libs/dojo/1.9.1/dojo/dojo.js'&gt;&lt; /script&gt; 在 index.html 文件中。

我们在这里创建自己的自定义包。这可能适用于您的模块、小部件等。包 位置将映射到您存储自定义 dojo 文件的 javascript 目录。 例如,myModules 可以在 /js/modules 目录中找到。您将参考任何自定义 dojo 文件通过"myModules/MyModule" 定位并加载"/myModules/MyModule.js" 文件。

有关baseURL 的解释,请参阅:http://dojotoolkit.org/documentation/tutorials/1.9/hello_dojo/ “定义和要求模块”。这段代码注册了我们自己的包的正确位置,所以 我们可以从 CDN 加载 Dojo,同时仍然能够加载本地模块。

我创建了一个名为"app" 的包,如下所示。这就是我在项目中初始化应用程序的方式。 这是为了让我能够尽我所知地保持代码分离。它已加载并 在 index.html 页面中调用。所以我给它一个app的包名。它物理上位于 js/controller/Controller.js 文件。

这个dojoConfig对象在index.html中使用,必须先加载&lt; script src='...dojo.js' &gt;标签。

var dojoConfig = 
    async: true,
    tlmSiblingOfDojo: false,
    baseUrl: location.pathname.replace(/\/[^/]*$/, ''),
    packages: [
         name: "myModules", location: "js/modules" ,
         name: "app", location: "js/controller", main: "Controller" 
    ]
;

如果您选择在您自己的服务器上托管 dojo 文件,您可以像下面这样引用它们。假设dojo js文件位于"/js/dojo/*"目录下。

packages: [
         name: "dojo", location: "dojo/dojo" , 
         name: "dijit", location: "dojo/dijit" ,
         name: "dojox", location: "dojo/dojox" ,
         name: "myModules", location: "js/modules" ,
         name: "app", location: "js/controller", main: "Controller" 
    ]

/js/controller/Controller.js

这是我用来初始化网络应用程序的控制器。

define(["myModules/MyFirstModule"], function(MyFirstModule) 

    //Private Variables...
    var privateVariable1 = "Welcome to my Dojo Application!";
    var privateVariable2;

    /**
     * init. This is a private function that is only available within this object.
     */
    init = function() 
        // proceed directly with startup
        console.log("Startup functions are firing...");

        //Render our "form" which only contains a single text box.
        renderForm();
    ,

    renderForm = function() 
        MyFirstModule.createForm("appBody");
    

    /**
     * Enclose all public methods in the return object
     */
    return 

        /**
         * main. This is a public function that can be called from other code.
         */
        main: function() 

            //Run init() method.
            init();
        ,

        /**
         * getWelcomeMessage. This public function returns the value of the privateVariable1.
         * This mimics a getter method.
         */
        getWelcomeMessage: function() 
            return privateVariable1;
        
    ;

); //end define

/js/modules/MyFirstModule.js

这是一个自定义模块的示例。 Controller 类需要它作为依赖项。

define([
    //The required dependencies for this module.
    "dojo/dom", "dojo/on", "dijit/form/TextBox", "dijit/form/Button"
], function(dom, on, TextBox, Button)
    // Once all modules in the dependency list have loaded, this
    // function is called to define the myModules/myFirstModule module.
    //
    // The dojo/dom module is passed as the first argument to this
    // function; additional modules in the dependency list would be
    // passed in as subsequent arguments (on, TextBox, and Button).

    // Private variables
    var firstNameTextBox;
    var submitButton;

    privateFunction = function() 
        console.log("I am a private function. I can only be called from this class.");
    ;

    // This returned object becomes the defined value of this module when called elsewhere.
    return 
        /**
         * createForm. This method creates a simple form. Textbox and button.
         * @param placeMeHere This is where to place the form elements. In this demo, the are placed in the 
         * body of the html document. This is executed in the Controller class.
         */
        createForm: function(placeMeHere) 

            //Create new TextBox.
            firstNameTextBox = new TextBox(
                name: "firstname",
                value: "" /* no or empty value! */,
                placeHolder: "type in your name"
            , "firstname");

            //Place me in the DOM.
            firstNameTextBox.placeAt(placeMeHere);

            //Render 
            firstNameTextBox.startup();

            //Create Button
            submitButton = new Button(
                label: "Say Hi"
            , "submitButton");
            submitButton.placeAt(placeMeHere);
            submitButton.startup();

            //Greet the user.
            on(submitButton, "click", function(evt)
                console.log("Hi there, " + firstNameTextBox.get("value"));
            );

        
    ;
);

【讨论】:

感谢您的回复。不确定我是否理解...我实际上是在尝试调用 chklogin 函数,因为它被错误检查为未定义。我得到了 dojo 库的其余部分来加载,我只是不确定在哪里放置 chklogin 函数以便它工作。 好的,抱歉。我还建议使用 define() 将该代码移动到模块中。你试过Hello Dojo 教程了吗?它展示了如何使用 define 实现您的目标。 不,感谢您的帮助。我看了看,不是一个很好的读者。当有人告诉我时,我理解。我的理解是他们在 .js 文件中创建了一个名为 mymodule 的模块;然后在主程序中需要该模块(mymodule)并将其用作函数。因此,在我的例子中,创建一个名为 chklogin 的模块,然后 require 它,当用户单击按钮时,它将从主 require[] 函数中调用该模块 chklogin。正确的?很抱歉在这里过分,但我很难阅读文档。 你太棒了。太感谢了。这会让我继续前进。 不客气。我很欣赏这些客气话。如果您对示例有任何疑问,请提出建议。我的解释可能会很啰嗦,会失去重点。

以上是关于了解道场 AMD 加载功能未定义的主要内容,如果未能解决你的问题,请参考以下文章

加载组件时检查道具是不是未定义

5.10.0-kali7-amd64 中的 kallsyms_lookup_name 未定义错误

带有自定义 xib 的 TableCellView 未加载

MetaMask - RPC 错误:无法设置未定义的属性(设置“加载默认值”)错误

道场网格excel

Google 登录 - 未定义 googleUser