如何在 Backbone.js 中将视图代码分离为模型和控制器

How to separate view code into model and controller in Backbone.js

我有我的代码,它是一个基本的 TODO 列表,其中只有以下几行代码。

我面临的问题是几乎所有东西都挤在视图本身中。模型或集合中几乎没有任何代码行,而且也没有控制器。

这否定了我正在尝试实现的 backbone 中的 MVC。有什么方法可以从视图中删除代码并将其放入任何其他模块中吗?

(function($){
Backbone.sync = function(method, model, success, error){
    success();
}

var Item = Backbone.Model.extend({});
var List = Backbone.Collection.extend({
    model: Item
});

var ItemView = Backbone.View.extend({
    tagName: 'div', // name of tag to be created 
    events: {
        'click span.delete': 'remove'
    }, 
    initialize: function(){
        _.bindAll(this, 'render', 'unrender', 'remove'); // every function that uses 'this' as the current object should be in here
        this.model.bind('change', this.render);
        this.model.bind('remove', this.unrender);
    },
    render: function(){
        $(this.el).html("<span style='margin-left: 20px;'></span>"+this.model.get('part')+'<span class="delete" style="cursor:pointer; color:red; font-family:sans-serif;">[delete]</span>');
        return this; // for chainable calls, like .render().el
    },
    unrender: function(){
        this.model.destroy();
    }
});


var ListView = Backbone.View.extend({
    el: $('body'), // attaches `this.el` to an existing element.
    events: {
        'click button#add': 'addItem'
    },
    initialize: function(){
        _.bindAll(this, 'render', 'addItem'); // fixes loss of context for 'this' within methods

        this.collection = new List();
        this.collection.bind('add', this.appendItem); // collection event binder
        this.render(); // not all views are self-rendering. This one is.
    },
    render: function(){
        var self = this;
        $(this.el).append("<body style='margin: 0; padding: 0;' id='body'><div  style='margin: 20px;'><h1>TODO list in plain JS and JQuery</h1><input type='text' id='taskBox' autofocus/>");
        $(this.el).append("<span id='appendToSpan'></span>");
        $(this.el).append("<button style='margin-left: 20px;' id='add'>Add list item</button>");
        _(this.collection.models).each(function(item){ // in case collection is not empty
            self.appendItem(item);
        }, this);
    },
    addItem: function(){
        var item = new Item();
        var val = $(this.el).find('input#taskBox').val();
        $(this.el).find('input#taskBox').val('');
        //this.model.set({'part': val});

        item.set({'part': val});

        this.collection.add(item);
    },
    appendItem: function(item){
        var itemView = new ItemView({
            model: item
        });
        $('span#appendToSpan', this.el).append(itemView.render().el);
    }
});

var listView = new ListView();
})(jQuery);
  <!DOCTYPE html>
  <html>
  <head>
    <meta charset="utf-8">
    <title>TODO App</title>
  </head>
  <body>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.1/jquery.min.js"></script>
    <script src="http://ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js"></script>
    <script src="http://documentcloud.github.com/underscore/underscore-min.js"></script>
    <script src="http://documentcloud.github.io/backbone/backbone-min.js"></script>

    <script src="views/demo1View.js" type="text/javascript"></script>
    
  </body>
  </html>

Backbonejs 不是 MVC 框架。它更像是 MVP(P - 演示者)框架。换句话说,您可以将您的逻辑驻留在视图中,该视图在真正的 MVC 框架中扮演控制器的角色。

只是尝试分离组件的职责并使其尽可能简单。

我建议对您的代码进行以下重构:

(function($){
Backbone.sync = function(method, model, success, error){
    success();
}

var Item = Backbone.Model.extend({});
var List = Backbone.Collection.extend({
    model: Item
});

var ItemView = Backbone.View.extend({

    events: {
        'click .js-delete': 'remove'
    },
 
    template: _.template($('#itemViewTemplate').html()),
  
    initialize: function(){
        this.listenTo(this.model, 'change', this.render);
        this.listenTo(this.model, 'remove', this.unrender);
    },
    
    render: function() {
     this.$el.html(this.template(this.model.toJSON()));
        return this;
    },
    
    unrender: function(){
        this.$el.remove();
    }
});


var ListView = Backbone.View.extend({  
 
    events: {
       'click .js-addItem': 'addItem'
    },
            
    initialize: function(){
        this.listenTo(this.collection, 'add', this.appendItem);
    },
    
    render: function(){
        this.collection.each(this.appendItem, this);
        return this;
    },
    
    addItem: function(){
        var $input = this.$('input#taskBox')
        var val = $input.val();
      
        this.collection.add({part: val});
        
        // clear input                        
        $input.val('');            
    },

    appendItem: function(item){
        var itemView = new ItemView({
            model: item,
            template: this.template
        });
        
        this.$('#appendToSpan').append(itemView.render().el);
    }
});
 
// Initialize widget and empty collection
var listView = new ListView({
    el: 'body',
    collection: new List()
});

// Render collection
listView.render();

})(jQuery);
<!DOCTYPE html>
  <html>
  <head>
    <meta charset="utf-8">
    <title>TODO App</title>
    <style>
      body {
        margin: 0;
        padding: 0;
      }
     
      .container {
        margin: 20px;
      }

      .addButton {
         margin-left: 20px;  
         margin-top: 10px;
      }

      .item-name {
         margin-left: 20px;
      }

      .item-remove {
         cursor:pointer;
         color:red;
         font-family:sans-serif;
      }

    </style>
  </head>
  <body>
    <div class="container">
    <h1>TODO list in plain JS and JQuery</h1>
    <input type='text' id='taskBox' autofocus/>
    <div id='appendToSpan'></div>
    <button class="addButton js-addItem">Add list item</button>
   
    <!-- Item template -->
    <script type="text/template" id="itemViewTemplate">
       <span class="item-name"><%= part %></span>
       <span class="js-delete item-remove">[delete]</span>
    </script>

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.1/jquery.min.js"></script>
    <script src="http://ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js"></script>
    <script src="http://documentcloud.github.com/underscore/underscore-min.js"></script>
    <script src="http://documentcloud.github.io/backbone/backbone-min.js"></script>
    
  </body>
  </html>