【问题标题】:Reassign Backbone View to newly created DOM element将主干视图重新分配给新创建的 DOM 元素
【发布时间】:2011-12-14 21:16:38
【问题描述】:

我正在使用 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
  • 将结果添加到列表视图时,会创建一个 ResultView,它知道其父级并呈现自己
  • 为 ResultView 创建一个元素 li.result(默认主干行为)

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

<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 中吗?还是我看错了?

谢谢!

【问题讨论】:

    标签: javascript backbone.js


    【解决方案1】:

    我建议简单地从您的视图中触发渲染事件,然后在 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 来确保绑定事件。
    【解决方案2】:

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

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

    也就是说,如果您确实想保留服务器呈现的视图,我可能会在页面加载后对您的集合执行 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() 可确保您定义的任何事件仍然有效。

    【讨论】:

    • 感谢您的回复,但我认为这并不能解决我的问题;该元素是在渲染后创建的,因此“existingElement”永远不会发生。但也许我想要的东西无法完成(有点像第 22 条),所以无论如何我都会看看你的建议。谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-21
    • 2012-02-23
    • 1970-01-01
    • 2016-04-12
    • 2013-01-15
    相关资源
    最近更新 更多