道場AMD:require 内で関数を呼び出すことができません
-
09-12-2019 - |
質問
私は本当に Dojo の初心者ですが、Dojo バージョン 1.7.2 で新しいアプリケーションの開発を始めたので、関数に新しい AMD 構文を使用したいとも思いました。残念ながら、理解できないようです。:-(
私を最もイライラさせるのは、「require」ブロック内にある関数を単純に呼び出すことができないことです。たとえば、開くときに各行に複数のウィジェットを含む動的テーブルを作成するページがあります。次に、押すたびに空の行を 1 つ追加するボタンがあります。
AMD 構文がなければ、それは簡単です。
- すべての「dojo.require()」を HEAD に入れます
- 次に、テーブルとウィジェットを作成するための独自の関数を多数作成します。
- add row関数は、前の関数で入力したグローバル変数に簡単にアクセスできます
しかし、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」をもう一度実行しますか?それとも、完全なリストを含む 1 つの「require」内にすべての関数を入れますか?
2 番目の方法を実行する場合、ウィジェット イベントからこれらの関数をどのように呼び出すことができますか?
解決
最も簡単な方法は、独自のモジュールを定義することです。まずはこのチュートリアルをご覧ください。
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>
他のヒント
これを試して:
require([...], function() {
var myFunctions = dojo.getObject('myFunctions', true);
myFunctions.createNewRow = function(...) {
...
};
});
を使用してどこからでも関数を呼び出すことができるようになりました。
myFunctions.createNewRow();
「myFunctions」が不要な場合は、次のようにすることもできます
require([...], function() {
var createNewRow = function(...) {};
dojo.setObject('createNewRow', createNewRow);
});
Paul Grime が良い例を挙げてくれたので、いくつかの考えを共有したいと思います。
各関数ですべてのモジュールを定義するわけではありません。これはスペースの膨大な無駄です。ただし、モジュールを複数回ロードしようとしても、Dojo がロードするのは 1 回のみです。
これは私の最新プロジェクトの簡略化されたモジュールで、まったく意味のない機能が含まれています。
//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();
}