Dojo中的路由/模块化(单页应用程序)

时间:2012-07-27 18:34:04

标签: dojo

之前我和骨干一起工作,并且想知道在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();
});

utils.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样板实现此功能的最佳方法是什么。

1 个答案:

答案 0 :(得分:1)

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

从另一个方面来说,看看我前一段时间,我为“控制器”设置一个摘要,然后在其实现中构建一个视图。

Abstract

然后我有一个application控制器,它在菜单上执行以下操作。单击

  1. 会触发加载图标,
  2. 卸载当前窗格(如果表单不脏)
  3. 加载所需的模块(在主菜单存储中定义'routes')
  4. 设置视图窗格,其中包含新的,请求的
  5. 每个视图或者只是一个server-html页面,或者是使用声明的'oocms'控制器模块构建的。最简单的abstract implementation here 示例。每个都实现了卸载功能和启动功能,我们希望在拆解时取消引用存储或事件挂钩 - 反过来,断言存储在设置中被加载等。

    如果您希望使用模板,请将您的观点基于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);
    
            }
        })
    });