每个属性呈现的Backbone.js(每个视图多个小视图与多个模板)

时间:2013-01-10 07:20:21

标签: backbone.js render backbone-views

我有一个模型和一个视图。视图显示模型的属性,并允许用户操作这些属性。问题是,当一个属性被修改时,它会重新渲染整个视图,这会给我带来很多问题。

文本输入上的示例模糊事件将新输入保存到属性,从而触发渲染。这意味着如果用户直接点击该文本输入到同一视图上的按钮,则事件将永远不会触发,因为第一个触发的事件将模糊,导致整个视图重新渲染,从而丢失按钮点击事件。 / em>的

我有两个想法:

  1. 拥有单个视图,其中每个属性都位于单独的模板中。然后我绑定到特定的属性更改事件,在渲染中我只更新已更改属性的html。这看起来像是一个黑客,因为有很多工作要强制视图只更新已更改的属性。它会给已经很复杂的视图增加许多不必要的复杂性。
  2. 创建一个由视图组成的主视图,其中每个视图代表一个模型的属性。这将创建很多视图,几乎没有任何功能。
  3. 我似乎更喜欢2.选项。你怎么看?什么是最佳做法?有没有更好的方法来解决这个问题?

2 个答案:

答案 0 :(得分:1)

我认为你可以很容易地做到这一点。

退后一步,考虑一下你的活动约束力。您似乎直接将它们绑定在每个单独的元素之上,而不是使用父委托。

这是一个例子

Backbone.View.extend({
  el: $("div.parent"),
  events: function() {
    this.$el.on("click", "input[type=button]", function(){});
    // jquery cross browser on this
    this.$el.on("blur", "input[type=text]", function(){});
  },
  initialize: function() {
    this.model.bind("change", this.render, this);
  },
  render: function() {
    this.$el.html('<input type="text" /><input type="button" />');
  }
});

这是el及其结构的样子

<div class="parent">
  <input type="text" />
  <input type="button" />
</div>

所以这个。$ el指向div.parent。我可以不断地重新阅读这个内容。$ el,只要html结构没有改变,我就不必担心事件会被解除。另一个解决方案是,如果我真的不能进行委托,那么每当我再次渲染时,我都会调用events方法。

答案 1 :(得分:1)

就像你自己说的那样,你的两个选择看起来都非常复杂。但有时候,复杂性是一种必要的恶魔。但是,如果更新的字段相对简单(比如将值绑定到元素或输入字段),我只需更新DOM元素,而无需在其上创建其他视图/模板抽象。

假设你有一个模特:

var person = new Person({ firstName: 'John', lastName: 'Lennon', instrument:'Guitar' });

以及呈现以下模板的视图:

<div>First Name: <span class="firstName">{{firstName}}</span></div>
<div>Last Name: <span class="lastName">{{lastName}}</span></div>
<div>Instrument: <input class="instrument" value="{{instrument}}"></input></div>

您可以在视图中声明哪个属性更改应更新哪个元素,并将模型change事件绑定到更新它们的函数:

var PersonView = Backbone.View.extend({

  //convention: propertyName+"Changed"
  //specify handler as map of selector->method or a function.
  firstNameChanged:  { '.firstName': 'text' },
  lastNameChanged:   { '.lastName': 'text' },
  instrumentChanged: { '.instrument': 'val' },
  otherFieldChanged: function(val) { //do something else },

  initialize: function (opts) {
    this.model.on('change', this.update, this);
  },

  //called when change event is fired
  update: function(state) {
    _.each(state.changed, function(val, key) {
      var handler = this[key + "Changed"];
      //handler specified for property?
      if(handler) {
        //if its a function execute it
        if(_.isFunction(handler)) {
          handler(val);
        //if its an object assume it's a selector->method map
        } else if(_.isObject(handler)) {
          _.each(handler, function(prop, selector) {
            this.$(selector)[prop](val);
          }, this);              
        }
      }
    }, this);
  }

这样的解决方案无法扩展到非常复杂的视图,因为您必须将已归类的元素添加到DOM并在View代码中维护它们。但对于更简单的情况,这可能会很有效。

此外,如果它们自然地划分为多个部分,那么尝试构建多个较小视图的视图总是好的。这样您就可以避免单独更新单个字段的需要。