2

我以前与骨干合作过,想知道是否有类似的方法可以在 dojo 中实现这种模式。如果您有一个路由器并分别传递您的视图(如图层),然后您可以在其他地方(例如视图内部)添加它们的实习生功能,因此代码非常模块化并且可以很容易地更改/添加新内容。这段代码实际上是在 jquery 中(并且来自以前的项目),它是在 jquery/backbone.js 下开发单个应用程序页面的“常见”基本模式。

main.js

var AppRouter = Backbone.Router.extend({

routes: {
        "home"                  : "home"},
home: function(){

        if (!this.homeView) {
            this.homeView= new HomeView();
        }
        $('#content').html(this.homeView.el);

        this.homeView.selectMenuItem('home-link');
    }};

utils.loadTemplate(['HomeView'], function() {
    app = new AppRouter();
    Backbone.history.start();
});

实用程序.js

loadTemplate: function(views, callback) {

        var deferreds = [];

        $.each(views, function(index, view) {
            if (window[view]) {
                deferreds.push($.get('tpl/' + view + '.html', function(data) {
                    window[view].prototype.template = _.template(data);
                }));
            } else {
                alert(view + " not found");
            }
        });

        $.when.apply(null, deferreds).done(callback);
    }};

HomeView.js

window.HomeView = Backbone.View.extend({

    initialize:function () {
        this.render();
    },

    render:function () {
        $(this.el).html(this.template());
        return this;
    }

});

基本上,您只需传递 html 模板。可以通过此链接在任何地方调用此模式:

<li class="active"><a href="#home"><i class="icon-home"></i> Dashboard</a></li>

或者,使用 dojo 样板实现这一点的最佳方法是什么。

4

1 回答 1

1

这个主题的“样板”是一个 dojox.mvc 应用程序。参考在这里。

从另一个方面来看,看看我前一阵子的做法,我为“控制器”设置了一个抽象,然后在其实现中构建了一个视图。

抽象的

然后我有一个应用程序控制器,它在其 menu.onClick 上执行以下操作

  1. 触发加载图标,
  2. 卸载当前窗格(如果表单不脏)
  3. 加载它需要的模块(在主菜单商店中定义的“路线”)
  4. 设置视图窗格,其中包含一个新的、请求的窗格

每个视图要么只是一个 server-html 页面,要么是使用声明的“oocms”控制器模块构建的。这里是抽象实现的最简单示例。每个都实现了一个卸载功能和一个启动功能,我们希望在拆卸中取消引用存储或事件挂钩 - 反过来,断言存储在设置中被加载等。

如果你想使用模板,那么你的观点基于 dijit._TemplatedMixin

编辑

这是对我的 oocms 设置的简化说明,我不会将其基于 BorderLayout,而是将其设为 ContentPanes:

菜单的 JSON 示例,其中单个项目表示上述声明的视图

 {
    identifier: 'view',
    label: 'name',
    items: [
      { name: 'myForm', view: 'App.view.MyForm', extraParams: { foo: 'bar' } }
    ]
 }

文件“AppPackagePath/Application.js”中的基本应用程序控制器

请注意,代码尚未经过测试,但应该可以很好地了解如何实现这样的设置

 define(['dojo/_base/declare', 
"dojo/_base/lang",
"dijit/registry",
"OoCmS/messagebus", // dependency mixin which will monitor 'notify/progress' topics'
"dojo/topic",
"dojo/data/ItemFileReadStore",
"dijit/tree/ForestStoreModel",
"dijit/Tree"

], function(declare, lang, registry, msgbus, dtopic, itemfilereadstore, djforestmodel, djtree) {
    return declare("App.Application", [msgbus], {

        paneContainer: NULL,
        treeContainer: NULL,
        menuStoreUrl: '/path/to/url-list',
        _widgetInUse: undefined,
        defaultPaneProps: {},
        loading: false, // ismple mutex
        constructor: function(args) {
            lang.mixin(this, args);
            if(!this.treeContainer || !this.paneContainer) {
                console.error("Dont know where to place components")
            }
            this.defaultPaneProps = {
                id: 'mainContentPane'
            }
            this.buildRendering();
        },
        buildRendering: function() {
            this.menustore = new itemfilereadstore({
                id: 'appMenuStore',
                url:this.menuStoreUrl
            });
            this.menumodel = new djforestmodel({
                id: 'appMenuModel',
                store: this.menustore
            });
            this.menu = new djtree( {
                model: this.menumodel,
                showRoot: false,
                autoExpand: true,
                onClick: lang.hitch(this, this.paneRequested) // passes the item
            })
                            // NEEDS a construct ID HERE
            this.menu.placeAt(this.treeContainer)
        },
        paneRequested: function(item) {
            if(this.loading || !item) {
                console.warn("No pane to load, give me a menustore item");
                return false;
            }
            if(!this._widgetInUse || !this._widgetInUse.isDirty()) {
                dtopic.publish("notify/progress/loading");
                this.loading = true;
            }
            if(typeof this._widgetInUse != "undefined") {
                if(!this._widgetInUse.unload()) {
                    // bail out if widget says 'no' (isDirty)
                    return false;
                }
                this._widgetInUse.destroyRecursive();
                delete this._widgetInUse;
            }

            var self = this,
                modules = [this.menustore.getValue(item, 'view')];
            require(modules, function(viewPane) {
                self._widgetInUse = new viewPane(self.defaultProps);

                            // NEEDS a construct ID HERE

                self._widgetInUse.placeAt(this.paneContainer)
                self._widgetInUse.ready.then(function() {
                    self.paneLoaded();
                })
            });
            return true;
        },
        paneLoaded: function() {
            // hide ajax icons
            dtopic.publish("notify/progress/done");
            // assert widget has started
            this._widgetInUse.startup();
            this.loading = false;
        }
    })
})

文件“AppPackagePath/view/AbstractView.js”中的 AbstractView:

define(["dojo/_base/declare",
"dojo/_base/Deferred",
"dojo/_base/lang",
"dijit/registry",
"dijit/layout/ContentPane"], function(declare, deferred, lang, registry, contentpane) {

    return declare("App.view.AbstractView", [contentpane], {
        observers: [],      // all programmatic events handles should be stored for d/c on unload
        parseOnLoad: false,
        constructor: function(args) {
            lang.mixin(this, args)
            // setup ready.then resolve
            this.ready = new deferred();
            // once ready, create
            this.ready.then(lang.hitch(this, this.postCreate));
            // the above is actually not nescessary, since we could simply use onLoad in contentpane
            if(typeof this.content != "undefined") {
                this.set("content", this.content);
                this.onLoad();
            } else if(typeof 'href' == "undefined") {
                console.warn("No contents nor href set in construct");
            }
        },
        startup : function startup() {
            this.inherited(arguments);
        },
        // if you override this, make sure to this.inherited(arguments);
        onLoad: function() {
            dojo.parser.parse(this.contentNode);
            // alert the application, that loading is done
            this.ready.resolve(null);
            // and call render
            this.render();
        },
        render: function() {
            console.info('no custom rendering performed in ' + this.declaredClass)
        },
        isDirty: function() { return false; },
        unload: function() {
            dojo.forEach(this.observers, dojo.disconnect);
            return true;
        },
        addObserver: function() {
            // simple passthrough, adding the connect to handles
            var handle = dojo.connect.call(dojo.window.get(dojo.doc), 
                arguments[0], arguments[1], arguments[2]);
            this.observers.push(handle);
        }
    });

});

查看文件“AppPackagePath/view/MyForm.js”中的实现示例:

define(["dojo/_base/declare",
"dojo/_base/lang",
"App/view/AbstractView",
// the contentpane href will pull in some html
// in the html can be markup, which will be renderered when ready
// pull in requirements here
"dijit/form/Form",  // markup require
"dijit/form/Button" // markup require
], function(declare, lang, baseinterface) {
    return declare("App.view.MyForm", [baseinterface], {
        // using an external HTML file
        href: 'dojoform.html',
        _isDirty : false,
        isDirty: function() {
            return this._isDirty;
        },
        render: function() {
            var self = this;
            this.formWidget = dijit.byId('embeddedForm') // hook up with loaded markup
            // observer for children
            dojo.forEach(this.formWidget._getDescendantFormWidgets(), function(widget){
                if(! lang.isFunction(widget.onChange) )
                    console.log('unable to observe ' + widget.id);
                self.addObserver(widget, 'onChange', function() {
                    self._isDirty = true;
                });
            });
        // 
        },

        // @override
        unload: function() {
            if(this.isDirty()) {
                var go = confirm("Sure you wish to leave page before save?")
                if(!go) return false;
            }
            return this.inherited(arguments);

        }
    })
});
于 2012-07-28T18:13:40.773 回答