0

確かに、私はまだ Dojo の初心者であり、常に Javascript に弱いので、言い訳をしてずさんなコードまたは言語を使用します。

Spring Roo 1.2.1RELEASE で Dojo 1.7.1 を使用しています。Googleから CDM を介して Dojo をロードしています。

少し前に、自分のサイトで使用するカスタムの画像サムネイル ビューアを作成しました。これは、Spring Roo の load-scripts.tagx の djConfig にモジュールを追加することでインクルードし、ページが読み込まれるたびに実行されます。サムネイル ウィジェットは AMD のパターンに従っていません。

djConfig は次のとおりです。

  <script type="text/javascript">
    var djConfig = {
            parseOnLoad: false, 
            isDebug: false, 
            locale: '${fn:toLowerCase(userLocale)}',
            modulePaths:    {
                "message": "${message_dojo_url}",
                "img.ArtThumbnailWidget": "${artThumbnailWidget_dojo_url}",
                "img.ArtTableWidget": "${artTableWidget_dojo_url}",
            },
        };
  </script>

これがサムネイル用の JS です。

// img.ArtThumbnailWidget
dojo.provide("img.ArtThumbnailWidget");

dojo.require("dojo._base.declare");
dojo.require("dojo.parser");
dojo.require("dojo.ready");
dojo.require("dijit._WidgetBase");
dojo.require("dijit._TemplatedMixin");
dojo.require("dojox.image.LightboxNano");

// Create the widget
require([
         "dojo/_base/declare",
         "dojo/parser",
         "dojo/ready",
         "dijit/_WidgetBase",
         "dijit/_TemplatedMixin",
         "dojo/dom",
         "dojo/dom-construct",
         "dojo/on",
         "dojo/text!img/ArtThumbnailWidget/templates/ArtThumbnailWidget.html",
         "dojox/image/LightboxNano",
         "dojo/domReady!"
    ], function(declare, parser, ready, _WidgetBase, _TemplatedMixin, dom, domConstruct, on, template) {

    dojo.declare("img.ArtThumbnailWidget",[dijit._WidgetBase, dijit._TemplatedMixin], {
        /* Our properties will go here */

        // Art JSON object, default is null
        art: null,

        // Viewer ID (the username of the person looking at this image), which will default to null
        viewerId: null,

        // maxThumbnailSize is how large of an image to return for the thumbnail.  The back-end will resize the thumbnail accordingly
        maxThumbnailSize: 100,

        // maxImageSize is how large of an image to return for the LightboxNano.  The back-end will resize the image accordingly
        maxImageSize: 500,

        // Our template - important!
        templateString: template,

        // A class to be applied to the root node in our template
        baseClass: "artThumbnailWidget",

        // Specifies there are widgets in the template itself that need to be rendered as well
        widgetsInTemplate: true,

        // Competition-related vars
        competitionUrlBase: null,
        competitionButtonIconUrl: null,

        /* This is called once the DOM structure is ready, but before anything is shown */
        postCreate: function() {
            // Get a DOM node reference for the root of our widget
            var domNode = this.domNode;

            // Run any parent postCreate processes - can be done at any point
            this.inherited(arguments);

            if(this.art!=null && this.viewerId!=null && this.art.owner.name == this.viewerId) {     // If the view is the owner, add the toolbar
                // TODO: We need to clean this up, make it "prettier", and make the URLs more generic
                var toolbarNode = domConstruct.create("div", {}, this.containerNode);

                if(this.competitionUrlBase!=null) {
                    var url = this.competitionUrlBase;
                    if(url.indexOf('?')<0) {    // URL does not have a '?'
                        url = url+"?";
                    } else {    // URL has a '?', so we need to tack on and additional '&'
                        url = url+"&";
                    }
                    url = url+"username="+this.art.owner.name+"&artPieceId="+this.art.id;

                    var compButtonNode = domConstruct.create("a",
                            {
                                href: url,
                            },toolbarNode);
                    var compButtonImg = domConstruct.create("img",
                            {
                                src: this.competitionButtonIconUrl,
                                width: this.maxThumbnailSize/4,
                                height: this.maxThumbnailSize/4,
                            },compButtonNode);
                }
            }
        },

        /* This private method is used to re-set the node values when something changes  */
        _resetNodeValues: function() {
            if(this.art !=null) {
                // Using our thumbnailNode attach point, set its src value
                this.thumbnailNode.src = this.art.url+"?maxSize="+this.maxThumbnailSize;
                this.thumbnailNode.alt = this.art.title;
                this.thumbnailNode.width = this.maxThumbnailSize;
                this.thumbnailNode.height = this.maxThumbnailSize;

                // Now setup the link for the LightboxNano
                var lightboxNano = new dojox.image.LightboxNano({
                    href: this.art.url+"?maxSize="+this.maxImageSize,
                },this.thumbnailNode);
            }
        },

        /* This is called anytime the "art" attribute is set.  Consider is a "setter" method */
        _setArtAttr: function(av) {
            if (av != null) {
                // Save it on our widget instance - note that
                // we're using _set, to support anyone using
                // our widget's Watch functionality, to watch values change
                this._set("art", av);

                this._resetNodeValues();
            } else {
                // We could have a default here...would be an error, since we
                // shouldn't be calling this without an art object
            }
        },

        _setMaxThumbnailSizeAttr: function(ms) {
            // Save it on our widget instance - note that
            // we're using _set, to support anyone using
            // our widget's Watch functionality, to watch values change
            this._set("maxThumbnailSize", ms);

            this._resetNodeValues();
        },

        _setMaxImageSizeAttr: function(ms) {
            // Save it on our widget instance - note that
            // we're using _set, to support anyone using
            // our widget's Watch functionality, to watch values change
            this._set("maxImageSize",ms);

            this._resetNodeValues();
        }
    });     // End of the widget

});

今、別のカスタム コンポーネント、上記のサムネイルのテーブルを追加しようとしています。新しいコードはこの古いウィジェットを参照する必要がありますが、動作させることができないようです。

新しいテーブル ウィジェット (これまでのところ):

// in "img/ArtTableWidget"
define([
        "dojo/_base/declare", "dojo/parser", 
        "dijit/_WidgetBase", "dijit/_TemplatedMixin", 
        "dojo/dom", "dojo/dom-construct","img/ArtThumbnailWidget",
        "dojo/text!./ArtTableWidget/templates/ArtTableWidget.html"], 
    function(declare,parser,_WidgetBase,_TemplatedMixin, dom, domConstruct, ArtThumbnailWidget, template) {
        return declare("img.ArtTableWidget",[dijit._WidgetBase,dijit._TemplatedMixin], {
            // Default values for the ArtTable

            // The base URL to use for downloading the photos
            artUrlBase: null,

            // The base URL used for submitting competitions and the button URL
            newCompetitionUrlBase: null,
            newCompetitionButtonIconUrl: null,

            // Indicates what params on the URL are used to control page 
            // and size.  These will be appended to the URL as needed.
            pageNumberParameterName: "page",
            pageSizeNumberParameterName: "size",

            // Holds the page and size
            page: 1,
            size: 15,
            totalPages: 0,

            columns: 3,

            // Holds the current list of "art"
            artList: [],

            // The userid currently viewing
            viewerId: null,

            // Our HTML template
            templateString: template,

            baseClass: "artTableWidget",

            // Specifies there are widgets in the template itself that need to be rendered as well
            widgetsInTemplate: true,

            // Functions //

            postCreate: function() {
                this._load(this.page);
            },

            // Loads the given page
            _load: function(pageToLoad) {
                if(pageToLoad==null) {
                    pageToLoad=1;
                }

                // Generate the URL
                genUrl = this.artUrlBase.indexOf("?")>=0 ? this.artUrlBase+"&page="+pageToLoad+"&size="+this.size : this.artUrlBase+"?page="+pageToLoad+"&size="+this.size;

                // Make the call to the backend
                dojo.xhrGet({
                    url: genUrl,
                    handleAs: "json",
                    tableWidget: this,
                    load: function(data,ioArgs) {
                        this.tableWidget.page = data.page;
                        this.tableWidget.totalPages = data.totalPages;
                        this.tableWidget.artList = data.data;

                        this.tableWidget._updateTable();
                    }
                });
            },

            _updateTable: function() {
                // Fix the buttons at the bottom

                // Clear the artTable
                domConstruct.empty(this.artTable);

                // Loop through the art and build the rows
                tableRow = tableRow = domConstruct.create("tr",{},this.artTable);
                dojo.forEach(this.artList,function(art,index) {
                    if(index % columns == 0) {
                        tableRow = domConstruct.create("tr",{},this.artTable);
                    }
                    tableColumn = domConstruct.create("td",{style: { marginLeft: "auto", marginRight: "auto" }},tableRow);
                    var tnNode = new ArtThumbnailWidget({
                        art: art,
                        viewerId: this.viewerId,
                        competitionUrlBase: this.newCompetitionUrlBase,
                        competitionButtonIconUrl: this.newCompetitionButtonIconUrl,
                    });
                    tnNode.placeAt(tableColumn);
                });
            }
        });
});

しかし、Chrome で新しいコンポーネントを実行すると、dojo.js.uncompressed.js 行 1716 で一般的なエラーが発生します。エラーのメッセージは「multipleDefine」であり、添付されたオブジェクトは ArtTableWidget のようです。このオブジェクトを掘り下げると、上部の define() で定義されたすべての依存関係の配列のように見える「deps」メンバーに img/ArtThumbnailWidget が含まれていることに気付きましたが、「pack」メンバーは未定義です。 . モジュールなどをロードしていないだけだと思います。

エラー (コピー/貼り付けが正しく表示されない場合は申し訳ありません) は次のとおりです。

dojo.js.uncompressed.js:1716
Error
  arguments: undefined
  get stack: function getter() { [native code] }
  info: Object
  cacheId: 0
  cjs: Object
  def: function (declare,parser,_WidgetBase,_TemplatedMixin, dom, domConstruct, ArtThumbnailWidget, template) {
  deps: Array[8]
    0: Object
    1: Object
    2: Object
    3: Object
    4: Object
    5: Object
    6: Object
      cacheId: 0
      def: 0
      executed: 4
      injected: 2
      isAmd: false
      isXd: null
      mid: "img/ArtThumbnailWidget"
      pack: undefined
      pid: ""
      result: Object
      url: "/ArtSite/resources/img/ArtThumbnailWidget.js"
      __proto__: Object
    7: Object
    length: 8
    __proto__: Array[0]
    executed: 0
    injected: 2
    isAmd: false
    isXd: null
    mid: "img/ArtTableWidget"
    node: HTMLScriptElement
    pack: undefined
    pid: ""
    require: function (a1, a2, a3){
    result: Object
    url: "/ArtSite/resources/img/ArtTableWidget.js"
    __proto__: Object
  message: "multipleDefine"
  set stack: function setter() { [native code] }
  src: "dojoLoader"
  type: undefined
  __proto__: ErrorPrototype
  dojo.js.uncompressed.js:1719src: dojoLoader
  dojo.js.uncompressed.js:1719info: 
  Object
  dojo.js.uncompressed.js:1721.

ここで正しい軌道に戻るには、助けが必要です。

編集 1 dojoConfig の「パス」の代わりに以下を使用したことを除いて、BuffaloBuffalo の返信の情報を使用してすべてのモジュールを更新しました。

    <script type="text/javascript">
    var djConfig = {
            parseOnLoad: false, 
            isDebug: false, 
            locale: '${fn:toLowerCase(userLocale)}',
            packages: [
                 { name: "message", location: "${message_dojo_module_base_url}" },
                 { name: "img", location: "${img_dojo_module_base_url}" }
            ]
        };
  </script>

.js ファイルは見つかったようですが、dojo/textを使用してそこにロードされたテンプレートは見つかりませんでした。「./path/Template.html」と「/module/path/Template.html」をやってみましたが、前者はCDN(上記リンクのGoogle APIサイト)を介してURLを解決しようとするようで、後者は欲しいようです完全修飾パス。汚い方法のように思えるので、完全なパスを入れるためにシャッターを切ります。また、次のように dojoConfig へのパスを追加してみました。

        paths: [
             { "message" : "${message_dojo_module_base_url}" }
        ]

しかし、それはまったく役に立たないようで、Chrome の JS コンソールで非常に厄介なエラーが発生しました。

ここで正しく読んでいる場合、dojo/text はモジュールを使用しませんか?

4

2 に答える 2

1

正確な問題が何であるかを判断するのは難しいですが、私に飛び出すいくつかのことがあります。

1.7を使用している場合は、djConfigオブジェクトに名前を付ける必要がありdojoConfigます(dojoConfigは引き続き機能しますが、更新することもできます)。

プロパティは、modulePathsという名前になるように更新する必要がありますpathimg.ArtThumbnailWidgetとが共通のディレクトリにある場合img.ArtTableWidgetは、次のようなものを使用できます。

var dojoConfig = {
            parseOnLoad: false, 
            isDebug: false, 
            locale: '${fn:toLowerCase(userLocale)}',
            paths:    {
                "message": "${message_dojo_url}",
                "img": "${art_module_url}"
            }
        };

2つ目は、img.ArtThumbnailWidgetのレガシー/amdローダースタイルの混合です。あなたはAMDスタイルで99%の道のりです。あなたがする必要があるのは

  1. dojo.provideとdojo.requiresを削除します
  2. に更新require([],function(){..});するdefine([],function(){..});
  3. グローバルではなくローカル変数を使用するように宣言の参照を更新します。

    //ArtThumbnailWidget
    define('img/ArtThumbnailWidget', [
        "dojo/_base/declare",
        "dojo/parser",
        "dojo/ready",
        "dijit/_WidgetBase",
        "dijit/_TemplatedMixin",
        "dojo/dom",
        "dojo/dom-construct",
        "dojo/on",
        "dojo/text!img/ArtThumbnailWidget/templates/ArtThumbnailWidget.html",
        "dojox/image/LightboxNano",
        "dojo/domReady!"
        ], function (declare, parser, ready, _WidgetBase, _TemplatedMixin, dom, domConstruct, on, template) {
    
      return declare("img.ArtThumbnailWidget", [_WidgetBase, _TemplatedMixin], {
        /* Our properties will go here */
    
        // Art JSON object, default is null
        art: null,
    
        // Viewer ID (the username of the person looking at this image), which will default to null
        viewerId: null,
    
        // maxThumbnailSize is how large of an image to return for the thumbnail.  The back-end will resize the thumbnail accordingly
        maxThumbnailSize: 100,
    
        // maxImageSize is how large of an image to return for the LightboxNano.  The back-end will resize the image accordingly
        maxImageSize: 500,
    
        // Our template - important!
        templateString: template,
    
        // A class to be applied to the root node in our template
        baseClass: "artThumbnailWidget",
    
        // Specifies there are widgets in the template itself that need to be rendered as well
        widgetsInTemplate: true,
    
        // Competition-related vars
        competitionUrlBase: null,
        competitionButtonIconUrl: null,
    
        /* This is called once the DOM structure is ready, but before anything is shown */
        postCreate: function () {
          // Get a DOM node reference for the root of our widget
          var domNode = this.domNode;
    
          // Run any parent postCreate processes - can be done at any point
          this.inherited(arguments);
    
          if (this.art != null && this.viewerId != null && this.art.owner.name == this.viewerId) { // If the view is the owner, add the toolbar
            // TODO: We need to clean this up, make it "prettier", and make the URLs more generic
            var toolbarNode = domConstruct.create("div", {}, this.containerNode);
    
            if (this.competitionUrlBase != null) {
              var url = this.competitionUrlBase;
              if (url.indexOf('?') < 0) { // URL does not have a '?'
                url = url + "?";
              } else { // URL has a '?', so we need to tack on and additional '&'
                url = url + "&";
              }
              url = url + "username=" + this.art.owner.name + "&artPieceId=" + this.art.id;
    
              var compButtonNode = domConstruct.create("a", {
                href: url,
              }, toolbarNode);
              var compButtonImg = domConstruct.create("img", {
                src: this.competitionButtonIconUrl,
                width: this.maxThumbnailSize / 4,
                height: this.maxThumbnailSize / 4,
              }, compButtonNode);
            }
          }
        },
    
        /* This private method is used to re-set the node values when something changes  */
        _resetNodeValues: function () {
          if (this.art != null) {
            // Using our thumbnailNode attach point, set its src value
            this.thumbnailNode.src = this.art.url + "?maxSize=" + this.maxThumbnailSize;
            this.thumbnailNode.alt = this.art.title;
            this.thumbnailNode.width = this.maxThumbnailSize;
            this.thumbnailNode.height = this.maxThumbnailSize;
    
            // Now setup the link for the LightboxNano
            var lightboxNano = new LightboxNano({
              href: this.art.url + "?maxSize=" + this.maxImageSize,
            }, this.thumbnailNode);
          }
        },
    
        /* This is called anytime the "art" attribute is set.  Consider is a "setter" method */
        _setArtAttr: function (av) {
          if (av != null) {
            // Save it on our widget instance - note that
            // we're using _set, to support anyone using
            // our widget's Watch functionality, to watch values change
            this._set("art", av);
    
            this._resetNodeValues();
          } else {
            // We could have a default here...would be an error, since we
            // shouldn't be calling this without an art object
          }
        },
    
        _setMaxThumbnailSizeAttr: function (ms) {
          // Save it on our widget instance - note that
          // we're using _set, to support anyone using
          // our widget's Watch functionality, to watch values change
          this._set("maxThumbnailSize", ms);
    
          this._resetNodeValues();
        },
    
        _setMaxImageSizeAttr: function (ms) {
          // Save it on our widget instance - note that
          // we're using _set, to support anyone using
          // our widget's Watch functionality, to watch values change
          this._set("maxImageSize", ms);
    
          this._resetNodeValues();
        }
      }); // End of the widget
    });
    

レガシースタイルとamdスタイルの組み合わせArtThumbnailWidgetが混乱を招いているのではないかと思いますArtTableWidget

于 2012-05-09T14:09:04.457 に答える
0

ですから、はい、ここで間違っている可能性があることがたくさんあります。より小さな例を機能させることはできますか?

  1. ブラウザーの開発者ツールの [ネットワーク] タブをチェックして、何を読み込もうとしているかを確認することお勧めします。これは通常、モジュールの解決に役立ちます。非同期モードではなく同期で実行することも、そこでの診断に役立ちます。
  2. img.ArtThumbnailWidget の代わりに img/ArtThumbnailWidget を modulePaths に登録する必要がありますか?
  3. 長期的には、モジュールごとではなくパッケージを登録することをお勧めします...
  4. ウィジェットで dojo/text!img/ArtThumbnailWidget/templates/ArtThumbnailWidget.html の代わりに dojo/text!./templates/ArtThumbnailWidget.html を参照できるはずですが、これは、ウィジェットの読み込み。(モジュールの require は、モジュールに対して相対的に処理されます。)
于 2012-05-09T16:11:23.073 に答える