将Backbone视图重新分配到新创建的DOM元素上

4

我正在使用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(默认Backbone行为)

这是我用来渲染搜索结果的模板(简化版):

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

这是我的难题,你可能也遇到过:我在Backbone ResultView中定义了一个li.result,并在模板中也定义了它。但我做不到的是:
  • 将ResultView绑定到模板中的li.result,因为它还不存在于DOM中
  • 从模板中删除li.result,因为我仍然需要在服务器端呈现页面,以供那些没有启用JavaScript的人使用
有没有一种(优雅的)方法来重新分配Backbone视图到实例化后的元素上?或者简单地说,我能否将ResultView引用到临时元素上,渲染模板,然后将其移动到ul#result中?还是我从错误的角度看待了这个问题?
谢谢!
2个回答

2
我建议从你的视图中简单地触发一个渲染事件,然后在onRendered回调函数中执行你的操作,代码如下:
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');
}

谢谢您!我实际上将您的答案与Scott Harvey的答案结合起来使用了;我使用了渲染触发器,重新分配了我的新li.result,然后使用@delegateEvents确保事件被绑定。 - Phortuin

1

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

如果有可能,我会将页面渲染移至客户端,这将极大地帮助简化您的代码。

话虽如此,如果您确实想保留服务器端渲染视图,我可能会在页面加载后对您的集合执行fetch()以从服务器获取所有对象。然后,您可以调整ResultView initialize函数来进行以下检查。

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() 确保您定义的任何事件仍然有效。


谢谢您的回复,但我认为这并不能解决我的问题;该元素是在渲染后创建的,因此“existingElement”永远不会发生。但也许我想要的无法实现(有点像进退两难),所以我还是会尝试您的建议。谢谢。 - Phortuin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接