6

我正在为联系人管理器在骨干网中实现视图/编辑视图。网络建议创建一个带有子视图的 Contact 类,称为 ContactView 和 ContactEdit。问题是,这些需要在 DOM 中占用相同的 el,所以我不能将子项嵌套在父项中。那是因为从外部看,我希望父视图只引用联系人,就好像孩子是私有的一样。我试过这个,它在我第一次渲染()时工作:

initialize: function() {
    this.view[0] = new CL.Views.ContactView({model: this.model, el: this.el});
    this.view[1] = new CL.Views.ContactEdit({model: this.model, el: this.el});
},
render: function() {
    this.view[0].render();
    return this;
}

但是我不能交换意见。我尝试了 this.view[0].remove() 和我能想到的一切,但就是无法让浏览和编辑视图使用相同的 el 相互交换。

我认为这意味着在一个视图中包含两个模板并交换它们会更好,这已经大部分工作了。我认为它的backbone.js 不能很好地处理DOM 中同一级别的视图的继承。

我宁愿避免使用backbone.js 扩展,但愿意遵循它们实现的任何模式。我正在尝试以“正确”的方式执行此操作,因为查看/编辑是我们应用程序中表单的常见模式。

PS 陈述这个问题的另一种方式是,如果没有父视图包围它们,如何隐藏视图并将其替换为骨干.js 中的另一个视图?

提前感谢您提供的任何帮助。

4

3 回答 3

1

我不太明白您是想查看 a CollectionofModels还是要查看处理 single Model

如果是单个模型的视图,

那么你可以坚持一种观点。只需让一些事件监听您启用或禁用编辑功能的操作。(您甚至可以通过在 dom 元素上设置 contenteditable="true" 来做到这一点)

我强烈建议使用一些工具,如backbone.marionette或chaplinjs。他们将为您节省大量时间。

以下示例适用于 Backbone.Marionette

示例模板

<script type="text/template" id="contact-view-template">
  <span data-bind="firstName"></span>
  <span data-bind="lastName"></span>
  <span data-bind="email"></span>
  <a href="#" data-action="edit">
  <a href="#" data-action="save" style="display:none">
</script>

视图代码:

ContactView = Marionette.ItemView.extend({
  template:"#contact-view-template",
  events:{
    "click [data-action=edit]":"edit",
    "click [data-action=save]":"save"
  },
  edit:function(){
    this.$("[data-action=edit]").hide();
    this.$("[data-action=save]").show();
    this.$("[data-bind]").attr("contenteditable",true);
  },
  save:function(){
    var value = {};
    _.each(this.$("[data-bind]",function(el){
      value[el.dataset['bind']]= $(el).val() || $(el).text();
    }));
    this.model.set(value);
    // add your validation here
    this.model.save();
  }
});

如果你想拥有多个编辑视图,不仅仅是:

ContactListEditView = Marionette.CompositeView.extend({
  itemView:ContactView.extend({
    tagName:"li"
  }),
  itemViewContainer:"ul",
  template:_.template("<h1>ContactList</h1><p>feel free to edit</p><ul></ul>")
});

如果您需要 1 个编辑视图和多个不可编辑视图

(我希望我没有犯任何严重的错误):

ContactEditView = Marionette.ItemView.extend({
  template:"#contact-edit-view", // your template & bindings
  events:{
    "click [data-action=save]":"save"
  },
  save:function(){
    var value = {};
    _.each(this.$("[data-bind]",function(el){
      value[el.dataset['bind']]= $(el).val() || $(el).text();
    }));
    this.model.set(value);
    this.model.save();
  }
});


ContactListView = Marionette.CompositeView.extend({
  itemView:Marionette.ItemView.extend({
    template:"#contact-view-template",
    events:{
      "click [data-action=edit]":"edit"
    },
    edit:function(){
      this.trigger("edit",this);
    }
  }),
  regions:{
    "edit":"[data-region=edit]"
  },
  initialize:function(){
    this.on("itemview:edit",function(view){
      this.edit.show(new ContactEditView({model:view.model}));
    }.bind(this));
  }
});
于 2013-01-26T00:20:34.627 回答
0

如果我正确理解您的问题,您需要一个从基础继承的视图,View以便它们可以自由地使用相同的Model.

/** Declare base View with specific Model. */
var baseView = Backbone.View.extend({
    model: someModel
});

var contactView = baseView.extend({
   initialize: function() {
        /** Do work specific to contact view. */
   }
});

var editContactView = baseView.extend({
   initialize: function() {
       /** Do work specific to contact edit. */
   }
});

var mainView = Backbone.View.extend({
   initialize: function() {
       /** Initialize two contact views */
       new contactView({ });
       new editContactView({ });
   }
});
于 2013-01-25T23:23:39.160 回答
0

我认为您的问题源于您的父视图与子视图共享相同的元素。当您渲染ContactVieworContactEdit视图时,它会替换 DOM 元素,而当您remove是子视图时,它(根据定义)也会删除父视图元素,因为它们是相同的元素。

相反,您应该组合父视图,以便将子视图呈现容器元素中。就像是

<!-- .contact-container is the parent view el -->
<section class="contact-container">

</section>

然后将子视图渲染到容器中:

initialize: function() {
  //don't give the views an element, let them render into the detached
  //element generated by Backbone
  this.view[0] = new CL.Views.ContactView({model: this.model});
  this.view[1] = new CL.Views.ContactEdit({model: this.model});
  this.currentViewIndex = 0;
},
render: function() {
  //replace the contents with the new view
  this.view[this.currentViewIndex].render();
  this.$el.html(this.view.el);

  return this;
},

swap: function() {
  var i = this.currentViewIndex;
  this.view[i].remove();
  //toggle current view between 0 and 1
  this.currentViewIndex = i === 0 ? 1: 0;
  this.render();
}

然后你得到

<!-- .contact-container is the parent view el -->
<section class="contact-container">
  <div><!-- your child element --></div>
</section>
于 2013-01-25T10:22:31.340 回答