将主干视图重新分配给新创建的DOM元素

Reassign Backbone View to newly created DOM element

本文关键字:创建 新创建 DOM 元素 新分配 分配 视图      更新时间:2023-09-26

我正在使用Backbone结合CoffeeScript和Handlebars创建一个搜索结果页面。我有两个视图:一个用于结果列表(ListView),第二个视图用于单个结果(ResultView)。简化代码:

ListView = Backbone.View.extend
  el: $("ul#results")
  ...
  addItem: (result) ->
    resultView = new ResultView({
      model: result
    })
    resultView.parentView = this
    this.el.append(resultView.render().el)
ResultView = Backbone.View.extend
  tagName: "li"
  className: "result"
  events:
    ...

简短说明:

  • ListView被分配给ul#results
  • 当一个结果被添加到listview时,一个ResultView被创建,它知道它的父视图并呈现它自己
  • 为ResultView创建一个元素li.result(默认的骨干行为)

这是我用来呈现搜索结果的(简化)模板:

<li class="result">
   <h1>
     <a href="{{link}}">{{title}}</a>
   </h1>
   <p>{{snippet}}</p>
</li>
这是我的难题,你可能已经发现自己:我在我的主干ResultView中定义了一个li.result,在我的模板中定义了。我不能做的事:
  • 将ResultView绑定到我的模板中的li.result,因为它还不存在于DOM
  • 从我的模板中删除li.result,因为我仍然需要它来渲染那些没有启用JavaScript的页面服务器端

是否有一种方法(优雅地)重新分配一个骨干视图的元素后,它的实例化?或者简单地说,我可以引用ResultView到一个临时元素,呈现模板,然后将其移动到ul#result ?还是我看错了?

谢谢!

我建议简单地从视图中触发渲染事件,然后在onrender回调中执行操作,如下所示:

initialize: function() {
  this.bind('rendered', onRendered);
},
onRendered: function() {
   // do onRendered stuff
   // eg. remove an element from the template
},
render: function() {
  // your render stuff
  this.trigger('rendered');
}

我发现,当您尝试支持服务器端呈现视图和客户端视图时,事情总是会变得更加复杂。你在这里描述的场景就是一个很好的例子。

如果可能的话,我会将页面的呈现移到客户端,这将极大地帮助简化您的代码。

也就是说,如果你想保留服务器渲染视图,我可能会在页面加载后对你的集合执行fetch()以从服务器获取所有对象。然后,您可以调整ResultView初始化函数来执行以下检查。

ResultView = Backbone.View.extend
  initialize: (attributes) ->
    exisitingElement = $('result_' + attributes['id'])
    if exisitingElement?
      @el = exisitingElement 
      @delegateEvents()

然后你可以修改你的模板来包含一个唯一的id。

    <li id="result_{{id}}" class="result">
       <h1>
         <a href="{{link}}">{{title}}</a>
       </h1>
       <p>{{snippet}}</p>
    </li>

这样,ResultView将在向页面呈现新元素之前查找现有元素。在重新分配@el属性后手动调用delegateEvents()可以确保您定义的任何事件仍然有效。