17

我已经开发 Backbone 应用程序有一段时间了,并且刚刚开始学习将 Backbone 与 Require.js 一起使用。

在我正在重构的主干应用程序中,我定义了一个这样的命名空间:App.model.repo. 该模型在不同的视图中反复使用。我对一些集合做同样的事情,例如,App.collection.files. 这些模型和集合与初始索引文件请求一起引导。

我确实找到了这个示例,这看起来是获取引导数据的好方法。但是,我正在努力寻找在视图之间重用/共享这些模型和集合的最佳方法。

我能想到三种可能的解决方案。哪个最好,为什么?还是我完全错过了另一种解决方案?

解决方案 1

在索引中定义这些公共模块和集合(当它们被引导时),然后将它们作为选项(的initialize)传递给每个 Backbone 视图。

define(['jquery', 'underscore', 'backbone', 'handlebars', 'text!templates/NavBar.html'], 
    function($, _, Backbone, Handlebars, template){     
        return Backbone.View.extend({
            template: Handlebars.compile(template),
            initialize: function(options){
                this.repoModel = options.repoModel; // common model passed in
            }
        });
    }
);

就分离而言,这些看起来很干净,但很快就会变得时髦,到处都是大量的东西。

解决方案 2

定义一个globals模块,并为其添加常用的模型和集合。

// models/Repo.js
define(['backbone'],
    function(Backbone){
        return Backbone.Model.extend({
            idAttribute: 'repo_id'
        });
    }
);

// globals.js (within index.php, for bootstrapping data)
define(['underscore', 'models/Repo'], 
    function(_, RepoModel){     
        var globals = {};
        
        globals.repoModel = new Repo(<?php echo json_encode($repo); ?>);
        
        return globals
    }
);

define(['jquery', 'underscore', 'backbone', 'handlebars', 'text!templates/NavBar.html', 'globals'], 
    function($, _, Backbone, Handlebars, template, globals){
        var repoModel = globals.repoModel; // repoModel from globals
        
        return Backbone.View.extend({
            template: Handlebars.compile(template),
            initialize: function(options){

            }
        });
    }
);

这个解决方案是否打败了 AMD 的全部观点?

解决方案 3

让一些模型和集合返回一个实例,而不是一个构造函数(有效地使它们成为单例)。

// models/repo.js
define(['backbone'],
    function(Backbone){
        // return instance
        return new Backbone.Model.extend({
            idAttribute: 'repo_id'
        });
    }
);

// Included in index.php for bootstrapping data
require(['jquery', 'backbone', 'models/repo', 'routers/Application'],
    function($, Backbone, repoModel, ApplicationRouter){
        repoModel.set(<?php echo json_encode($repo); ?>);

        new ApplicationRouter({el: $('.site-container')});
        Backbone.history.start();
    }
);

define(['jquery', 'underscore', 'backbone', 'handlebars', 'text!templates/NavBar.html', 'models/repo'], 
    function($, _, Backbone, Handlebars, template, repoModel){
        // repoModel has values set by index.php
        
        return Backbone.View.extend({
            template: Handlebars.compile(template),
            initialize: function(options){

            }
        });
    }
);

我担心这会让人对什么是构造函数和什么是实例感到真正的困惑。

结尾

如果你读到这里,你太棒了!感谢您抽出宝贵的时间。

4

3 回答 3

4

就我而言,我更喜欢选项 3。不过,为了防止混淆,我将每个单例实例都放在了它们自己的名为instances. 另外,我倾向于将 与model/collection模块instance分开。

然后,我只是打电话给他们:

define([
  "instance/photos"
], function( photos ) { /* do stuff */ });

我更喜欢这个选项,因为每个模块都被迫定义其依赖项(例如,通过命名空间不是这种情况)。解决方案 2 可以完成这项工作,但如果我使用的是 AMD,我希望我的模块尽可能小——再加上保持它们小,以便更容易进行单元测试。

最后,关于单元测试,我可以在单元测试中重新定义实例以使用模拟数据。所以,当然,选项3。

您可以在我正在开发 ATM 的开源应用程序上看到此模式的示例:https ://github.com/iplanwebsites/newtab-bookmarks/tree/master/app

于 2013-02-14T20:01:31.893 回答
1

我会看看这个示例回购https://github.com/tbranyen/github-viewer

它是主干样板的工作示例(https://github.com/tbranyen/backbone-boilerplate

Backbone Boiler plate 做了很多不必要的麻烦,但它真正有用的是它为开发复杂的 javascript 应用程序的常见模式提供了一些明确的方向。

我会试着在今天晚些时候回来更具体地回答你的问题(如果有人没有打败我:)

于 2013-02-14T20:02:16.507 回答
1

我更喜欢解决方案 1。通常最好避免 使用 singletons,并且使用 globals 也是要避免的,特别是因为您使用的是 RequireJS。

以下是我能想到的解决方案 1 的一些优点:

它使视图代码更具可读性。第一次看这个模块的人可以通过查看initialize它使用的模型立即看出它的功能。如果您使用全局变量,则可能会在文件中的 500 行访问某些内容。

它使为视图代码编写单元测试变得更加容易。因为您可能会在测试中传递假模型。

于 2013-02-14T21:19:33.020 回答