在 Backbone 应用程序中,按照惯例,模型、视图和集合的工作是啥

Posted

技术标签:

【中文标题】在 Backbone 应用程序中,按照惯例,模型、视图和集合的工作是啥【英文标题】:In a Backbone app what is work of model, views and collections by convention在 Backbone 应用程序中,按照惯例,模型、视图和集合的工作是什么 【发布时间】:2011-10-05 09:21:49 【问题描述】:

我现在正在使用backbonejs mvc javascript库开发一个简单的应用程序。只是为了展示它是多么简单的是html

示例 HTML

<div class="container">
    <div>
        <label>
            Name:
            <input id="txtName" type="text" title="Type your name please" /></label>
        <button id="btnSubmit" type="button" value="Submit">
            Submit</button>
    </div>
    <div id="names">
    </div>
</div>

操作

这就是我想要应用程序做的所有事情。

    用户键入名称(或一些字母数字字符串)并单击提交。

    验证后的值(我想这就是他们所说的模型)将被发送到 RESTful 服务。

    服务将返回相同的字符串以及数据库保存操作的状态。

我现在很困惑点击事件将在哪里处理(它在模型中吗?),然后应该在哪里调用渲染方法?(它在视图中)。您将在下面找到我到目前为止管理的脚本

模型.js

//store a global reference to model
    window["model"] = Backbone.Model.extend(

        defaults:  name: "Type your name"
        ,
        validate: function () 

        

    );

View.js

//store a global reference to view
window["view"] = Backbone.View.extend();

没有什么可说的:(

Application.js

//when every thing is ready kick of the application
$(document).ready(function () 


    var modelInstance = new model();


);

    那么我应该将点击事件添加到 application.js 或 model.js 中的按钮吗?这是约定/最佳实践吗?

    我是否可以将从服务返回的名称集合呈现到#names,并将数据库插入状态呈现到容器上方的另一个div?视图可以同时渲染两个视图吗?

【问题讨论】:

【参考方案1】:

所以,这里有一个免责声明:如果这就是您的应用程序所做的全部,那么 Backbone 就太仪式化了。当应用程序变得更复杂且移动部件更多时,Backbone 会变得非常棒。

话虽如此,我已经创建了一个 jsFiddle 来强调您可以如何使用 Backbone 来完成您想做的事情:http://jsfiddle.net/BrianGenisio/CZwnk/4/

基本上,您有一个Person 模型和一个People 集合来保存Person 模型。然后您将拥有三个视图:NewPersonView 这是用于输入数据的表单,它负责将新项目添加到 People 集合中。然后你有一个PeopleView 视图,它负责显示People 集合,它将观察集合并显示任何添加。最后是PersonView,它负责展示一个单独的Person模型。

当这一切结合在一起时,它看起来有点像这样:

HTML:

<script id="new_person_template" type="text/template">    
    <label>
        Name:
        <input id="txtName" type="text" title="Type your name please" />
    </label>
    <button id="btnSubmit" type="button" value="Submit">Submit</button>
</script>

<script id="person_template" type="text/template">    
    Hello, my name is <%= name %>
</script>

<div id="container">

</div>

JavaScript

window.app = ;

window.app.Person = Backbone.Model.extend(
    defaults:  name: "Type your name" ,
    validate: function ()  
);

window.app.People = Backbone.Collection.extend(
    model: window.app.Person
);

window.app.NewPersonView = Backbone.View.extend(
    template: _.template($("#new_person_template").html()),
    initialize: function () 
        _.bindAll(this, 'submit');
    ,
    events:
    
        "click #btnSubmit": "submit"
    ,
    render: function () 
        $(this.el).html(this.template());
        return this;
    ,
    submit: function (x, y, z) 
        // If you want this to go up to the server and sync, do this instead:
        // this.model.create(name: $("#txtName").val());
        // but since we don't really have a server right now, we'll just create and add
        var person = new window.app.Person(name: $("#txtName").val());
        this.model.add(person);
    
);

window.app.PersonView = Backbone.View.extend(
    tagname: "li",
    template: _.template($("#person_template").html()),
    render: function() 
        $(this.el).html(this.template(this.model.toJSON()));
        return this;
    
);

window.app.PeopleView = Backbone.View.extend(
    tagName: "ul",

    initialize: function() 
        _.bindAll(this, "render", "renderPerson");
        this.model.bind("add", this.renderPerson);
    ,

    render: function() 
       console.log("rendering");
       this.model.each(this.renderPerson);
       return this;
    ,

    renderPerson: function(person) 
        var personView = new window.app.PersonView(model: person);
        $(this.el).append(personView.render().el);
    
);


$(document).ready(function () 

    var people = new window.app.People();
    var newPersonView = new window.app.NewPersonView(model: people);
    var peopleView = new window.app.PeopleView(model: people);

    $("#container").html(newPersonView.render().el);
    $("#container").append(peopleView.render().el);
);

【讨论】:

我当然同意免责声明。小型应用程序将是学习新事物的方式(我就是这样做的)。感谢您的完整回答和小提琴垫【参考方案2】:

我会在视图中单击 在我看来,您需要 2 个视图,1 个是包含整个应用程序的 appview 另一个只是您在列表中呈现的每个用户模型的视图。

这是你的用户模型

var User = Backbone.Model.extend(
  defaults: 
    id: 0,
    name: 'no-name'
  
);

这是你的收藏

var Users = Backbone.Collection.extend(

  model: User,

  create : function(model, options) 
    var coll = this;
    options || (options = );
    if (!(model instanceof Backbone.Model)) 
      model = new this.model(model, collection: coll);
     else 
      model.collection = coll;
    
    var success = function(savedModel, resp) 
      coll.add(savedModel);
      if (options.success) options.success(nextModel, resp);

      // fire success event
      coll.trigger("savesuccess", savedModel);
    ;
    var error = function(resp) 
      if(options.error) options.error(resp);

      // fire error event
      coll.trigger("saveerror");
    
    return model.save(null, success : success, error : error);
  
);

所以这是一个可能的用户视图

var UserRow = Backbone.View.extend(

  tagName: "li",

  initialize: function()
    _.bindAll(this, 'render');
    this.model.bind('change', this.render);
  ,

  className: "user",

  render: function() 
    var user = this.model;
    $(this.el).html(user.get('name'));
    return this;
  

);

这是你的 appView

var AppView = Backbone.View.extend(

  el: 'body',

  events: 
    'click button#btnSubmit': 'addUser'
  ,

  initialize: function()
    this.collection = new Users();
    this.collection.bind('add', this.appendUser);
    this.collection.bind('savesuccess', this.saveSuccess);
    this.collection.bind('saveerror', this.saveError);
    this.counter = 0;
    this.render();
  ,

  addUser: function()
    this.counter++;
    var user = new User();
    user.set(
      id: user.get('id') + this.counter,
      name: $('#txtName', this.el).val()
    );
    this.collection.add(user);
  ,

  appendUser: function(user)
    var userRow = new UserRow(
      model: user
    );
    $('ul#names', this.el).append(userRow.render().el);
  ,

  saveSuccess: function(user)
    alert('successfully saved, you can append something to the AppView DOM to show that saving was successful ...');
  ,

  saveError: function()
    alert('failed to save, you can append something to the AppView Dom to show that saving failed, or remove the item again ...');
  
);

你在这里初始化它

var App = new AppView();

如您所见,将项目保存到数据库后并不会呈现项目本身,而是将其添加到集合中,appView 绑定到集合的添加事件并将新用户附加到您的列表中。

由于在集合上使用了 create 函数,CRUD 服务器连接会自动工作。

这里的想法是您不需要用户主干事件,从您的集合成功保存或错误保存中触发事件,并让任何视图绑定到该事件以使某些事情发生保存成功与否时的画面。

【讨论】:

+1。 Backbone 如此酷的原因之一是没有“正确”的方式。它提供了结构。之后,您可以创建自己的方式。我认为重要的是你找到一种有效的模式并坚持下去。 你这么认为吗?我敢打赌,即使以我的工作方式,我也能从其他模式中学到一两个东西。尽管我确信我的工作方式对我来说已经足够好,但我一直在努力寻求更好、更短、更高性能的解决方案,即使我有一种适合我的方式,其他人可能会想出更短的方式,或者是更具可扩展性。尽管您是对的,但骨干提供了结构,您可以选择如何使用它以及如何使用它! @Sander +1 你在 SO 上保存了另一个问题 :)

以上是关于在 Backbone 应用程序中,按照惯例,模型、视图和集合的工作是啥的主要内容,如果未能解决你的问题,请参考以下文章

Backbone.js 模型和集合的最佳实践

对 Backbone + React 应用程序中的模型的困惑

Backbone.js:组合多个模型的复杂视图

如何在 Backbone 中获取单个模型?

Backbone 应用程序中嵌套表单视图的架构

Backbone.js:在现实世界的应用程序中呈现集合