【问题标题】:Backbone.js per attribute rendering (multiple small views vs multiple templates per view )Backbone.js 每个属性渲染(多个小视图与每个视图多个模板)
【发布时间】:2013-01-10 07:20:20
【问题描述】:

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

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

我有两个想法:

  1. 拥有一个视图,其中每个属性都位于单独的模板中。然后我绑定到一个特定的属性更改事件,并在渲染中只更新更改属性的 html。这似乎是一种 hack,因为要强制视图仅更新已更改的属性需要做很多工作。它会给已经很复杂的视图增加很多不必要的复杂性。
  2. 创建一个由视图组成的主视图,其中每个视图代表一个模型的属性。这将创建很多视图,几乎没有任何功能。

我似乎更喜欢 2. 选项。你怎么看?最佳实践是什么?有没有更好的处理方法?

【问题讨论】:

标签: backbone.js render backbone-views


【解决方案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>

所以 this.$el 指向 div.parent。我可以不断地重新渲染 this.$el 的内容,只要 html 结构不改变,我就不必担心事件会被解除绑定。另一种解决方案是,如果我真的不能做委托,我会在再次渲染时调用 events 方法。

【讨论】:

    【解决方案2】:

    就像您自己说的那样,您的两种选择似乎都非常复杂。但有时额外的复杂性是一种必要的邪恶。但是,如果更新的字段相对简单(例如将值绑定到元素或输入字段),我会简单地更新 DOM 元素,而无需在它们之上创建额外的 View/Template 抽象。

    假设你有一个模型:

    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 并在视图代码中维护它们。但对于更简单的情况,这可能效果很好。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-07-13
      • 1970-01-01
      • 1970-01-01
      • 2012-03-13
      相关资源
      最近更新 更多