骨干设计

Cor*_*ory 7 backbone.js

我刚开始使用Backbone.我经历了前两个很棒的PeepCode截屏视频,现在我正在深入研究未来应用的快速分离(无服务器端)模拟.

这是我想要建立的(大致).一系列五个文本框 - 让我们调用这些小部件.选中后,每个窗口小部件输入将显示一个窗格,其中显示与窗口小部件关联的任务,并允许用户创建新任务或销毁现有任务.

在这一点上,我想我有以下模型:

Widget
Task
Run Code Online (Sandbox Code Playgroud)

以下集合:

Tasks
Widgets
Run Code Online (Sandbox Code Playgroud)

以下视图(这是多毛的地方!)

WidgetListView
  - Presents a collection of Widgets
WidgetView 
  - sub-view of WidgetListView to render a specific Widget
TaskPaneView 
  - Presented when the user selects a Widget input
TaskCreateView 
  - Ability to create a new Task associated with selected Widget
TaskListView 
  - Presents a collection of Tasks for the given widget
TaskView 
  - Displays Task detail - sub-view of TaskListView
Run Code Online (Sandbox Code Playgroud)

假设这是合理的,那么当选择WidgetView时,技巧就变成了如何显示TaskPaneView.而且,TaskPaneView应该如何呈现TaskCreateViews和TaskListViews.

这里真正的问题是:一个级联是否跨视图呈现事件?Root视图是否允许知道子视图并显式呈现它们?这应该是事件驱动的吗?

抱歉,如果这是一个开放式的问题,只是希望有人以前会看到类似的东西,并能够指出我正确的方向.

谢谢!

Chr*_*rdi 15

绝对让它成为事件驱动.另外,尽量不要创建紧密耦合的视图.松散的耦合将使您的代码更易于维护和灵活.

查看关于事件聚合器模型和主干的这篇文章:

http://lostechies.com/derickbailey/2011/07/19/references-routing-and-the-event-aggregator-coordinating-views-in-backbone-js/

简短的版本是你可以这样做:

var vent = _.extend({}, Backbone.Events);
Run Code Online (Sandbox Code Playgroud)

并使用vent.trigger和vent.bind来控制你的应用程序.


Mos*_*man 12

Pre ps:我用你在下面写的代码为你做了一个要点:https: //gist.github.com/2863979

我同意其他答案所建议的pub/sub('观察者模式').然而,我也会使用Require.js和Backbone的强大功能.

Addy Osmani写了几篇很棒!有关Javascript设计模式和构建Backbone应用程序的资源:

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ http://addyosmani.com/writing-modular-js/ http://addyosmani.github.com/backbone-fundamentals/

使用AMD(在Require.js中实现)以及Backbone的一个很酷的事情是你解决了一些你通常遇到的问题.

通常,您将以某种命名空间的方式定义类并存储它们,例如:

MyApp.controllers.Tasks = Backbone.Controller.extend({})
Run Code Online (Sandbox Code Playgroud)

这是好的,只要你在一个文件中定义的大多数事情,当你开始添加越来越多的不同的文件到它会不太可靠的搭配,你必须开始关注你在不同的文件如何加载,controllers\Tasks.js以后models\Task.js等你当然可以按正确的顺序编译所有文件等,但它远非完美.

除此之外,非AMD方式的问题在于您必须更紧密地将视图嵌套在彼此内部.让我们说:

MyApp.classes.views.TaskList = Backbone.View.extend({ 
    // do stuff
});

MyApp.views.App = Backbone.View.extend({
    el: '#app',
    initialize: function(){
        _.bindAll(this, 'render');
        this.task_list = new MyApp.classes.views.TaskList();    
    },

    render: function(){
        this.task_list.render();
    }
});

window.app = new MyApp.views.App();
Run Code Online (Sandbox Code Playgroud)

一切都很好,但这可能成为一场噩梦.

使用AMD,你可以定义一个模块并给它一些依赖,如果你对它的工作方式感兴趣,请阅读上面的链接,但上面的例子看起来像这样:

// file: views/TaskList.js
define([], function(){

    var TaskList = Backbone.View.extend({
        //do stuff
    });

    return new TaskList();
});

// file: views/App.js
define(['views/TaskList'], function(TaskListView){

    var App = Backbone.View.extend({
        el: '#app',

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

        render: function(){
            TaskListView.render();
        }
    });

    return new App();
});

// called in index.html
Require(['views/App'], function(AppView){
    window.app = AppView;
});
Run Code Online (Sandbox Code Playgroud)

请注意,在视图的情况下,您将返回实例,我也会为集合执行此操作,但对于模型,我将返回类:

// file: models/Task.js
define([], function(){

    var Task = Backbone.Model.extend({
        //do stuff
    });

    return Task;
});
Run Code Online (Sandbox Code Playgroud)

起初看起来可能有点多,人们可能会认为"哇这太过分了".但是当你必须在许多不同的模块中使用相同的对象时,真正的力量变得清晰,例如集合:

// file: models/Task.js
define([], function(){

    var Task = Backbone.Model.extend({
        //do stuff
    });

    return Task;
});

// file: collections/Tasks.js
define(['models/Task'], function(TaskModel){

    var Tasks = Backbone.Collection.extend({
        model: TaskModel
    });

    return new Tasks();
});

// file: views/TaskList.js
define(['collections/Tasks'], function(Tasks){

    var TaskList = Backbone.View.extend({
        render: function(){
            _.each(Tasks.models, function(task, index){
                // do something with each task
            });
        }
    });

    return new TaskList();
});


// file: views/statistics.js
define(['collections/Tasks'], function(Tasks){

    var TaskStats = Backbone.View.extend({
        el: document.createElement('div'),

        // Note that you'd have this function in your collection normally (demo)
        getStats: function(){
            totals = {
                all: Tasks.models.length
                done: _.filter(Tasks, function(task){ return task.get('done'); });
            };

            return totals;
        },

        render: function(){
            var stats = this.getStats();

            // do something in a view with the stats.
        }
    });

    return new TaskStats();
});
Run Code Online (Sandbox Code Playgroud)

请注意,'Tasks'对象在两个视图中完全相同,因此相同的模型,状态等等.这比在一个点上创建Tasks集合的实例然后通过整个应用程序引用它更好.时间.

至少对我来说,使用带有Backbone的Require.js已经带走了一个令人费解的巨大片段,在哪里实例化.使用模块非常有帮助.我希望这也适用于你的问题.

请注意,你也可以将Backbone,Underscore和jQuery作为模块添加到你的应用程序中,尽管你不必这样做,你可以使用普通的脚本标签加载它们.