交换/交换/交换主干.js视图到位



我正在为联系人管理器在骨干网.js中实现视图/编辑视图。 Web 建议创建一个具有子视图的 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;
}

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

我认为这意味着最好在一个视图中有两个模板并交换它们,这已经大部分有效。 我认为它是骨干.js不能很好地处理 DOM 中同一级别视图的继承。

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

附言说明此问题的另一种方法是,如果没有父视图包围它们,如何隐藏视图并将其替换为 backbone.js 中的另一个视图?

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

我不太明白您是否想查看Models Collection,还是想要处理单个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));
  }
});

我认为您的问题源于您的父视图与子视图共享相同元素的事实。当您呈现ContactViewContactEdit视图时,它会替换 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>
如果我

正确理解您的问题,您需要一个继承自基本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({ });
   }
});

最新更新