在parent-view's元素中添加子视图元素

Backbone.js adding sub-view elements to parent-view's element

本文关键字:元素 添加 视图 parent-view      更新时间:2023-09-26

我有一个集合视图和一个模型视图,如下所示:

EventListView
|-- EventView

EventListView必须在一对多关系中显示多个EventViews。我使用下划线_.template()函数来构建我的视图模板。

这是我的EventView模板:

<h1>
    <span class="date"><%= prefix %><%= dateString %></span>
    <span class="title"><%= title %></span>
</h1>
<div class="caption"><%= caption %></div>

我的EventView渲染方法:

render: function () {
    this.$el.html(this.template(this.model.attributes));
    return this;
}
这是我的EventListView模板:
<h1>
    <% if(typeof(title) != "undefined") { print(title) } %>
</h1>
<%= events %>

它的渲染方法:

// this._EventViews is an array of eventView objects
render: function() {
    var templateData = {
        events: _.reduce(this._EventViews, function(memo, eventView) { return memo + eventView.$el.html(); }, "")
    }
    this.$el.html(this.template(templateData));
    return this;
}

我遇到的问题是,eventView.$el.html()只包含HTML在我的模板,但我需要利用tagName, classNameid属性的骨干视图支持的优势。

考虑如果我这样设置EventView:

return Backbone.View.extend({
    model: EventModel
,   tagName: 'article'
,   className: 'event'  
,   template: _.template(templateText)
,   render: function () {
        this.$el.html(this.template(this.model.attributes));
        return this;
    }
});

我想插入:

<article class="event" id="someID342">
    <h1>
       <span class="date">01/02/2010</span>
       <span class="title"></span>
       <div class="caption></div>
    </h1>
</article>

但是eventView.$el返回:

<h1>
   <span class="date">01/02/2010</span>
   <span class="title"></span>
   <div class="caption></div>
</h1>

如何插入整个eventView元素?不仅仅是innerHTML

在你的EvenListView模板中保留占位符

<h1><%- title %></h1>
<div class="js-events"></div>

然后呈现和追加子视图

render: function() {
    this.$el.html(this.template({title: 'Title'}));
    this.$events = this.$('.js-events');
    _.each(this._EventViews, function (eventView) {
        this.$events.append(eventView.render().$el);
    }, this);
    return this;
}

render()函数不应该负责处理view.el的设置。这是由Backbone_ensureElement函数中完成的,该函数在初始化视图时被调用。

同样,$.fn.html()函数只应该返回所选元素的内容。

你有很多选择,但我认为最灵活和可持续的方法是让每个子视图定义自己的模板。父视图只是附加了子元素的.el属性。

这种方法的优点是,你的模板只编译一次。对子元素的更新不需要重新渲染父元素和相邻元素。

这是一个JSBin

例子:

var ContainerView = Backbone.View.extend({
  tagName: "article",
  className: "event",
  id: "someID342",
  initialize: function(options){
    //the template will now be rendered
    this.childView = new ChildView()
    //the rendered child will now appear within the parent view
    this.el.appendChild( this.childView.el )
  }
})
var ChildView = Backbone.View.extend({
  tagName: "h1",
  dateString:"01/02/2010",
  prefix: "Date: ",
  caption: "What a wonderful date!:",
  title: "I am a title",
  template: _.template([
    '<h1>',
      '<span class="date"><%= prefix %><%= dateString %></span>',
      '<span class="title"><%= title %></span>',
    '</h1>',
    '<div class="caption"><%= caption %></div>'
  ].join("")),
  initialize: function(){
    this.render()
  },
  render: function(){
    // because you are only altering innerHTML
    // you do not need to reappend the child in the parent view
    this.el.innerHTML = this.template(this)
  }
})

我个人警告不要在Backbone中使用模板。我发现,简单地为你的应用程序的每个组件都有一个主干视图,以后编辑起来会容易得多。共享模板比共享视图难得多。当然,这取决于你的项目需求。