【问题标题】:Backbone view events losing delegation on parent view re-render主干视图事件在父视图重新渲染时失去委托
【发布时间】:2014-09-18 00:07:09
【问题描述】:

我已经看到这个问题出现了几次,但我自己无法解决 - 或者我不太明白答案。许多事情都在谈论使用.empty().append() 而不是.html() 以及确保始终引用视图的$el 值而不是直接访问DOM 的事情。还是没有骰子。

如果您查看这个 jsbin,您会发现更改选择框值会在第一次重新呈现包装器视图,但随后不会对后续更改执行任何操作 - 它会丢失其事件。

http://jsbin.com/fuvoba/7/edit(向任何讨厌咖啡脚本的人道歉)

知道为什么会发生这种情况吗?

非常感谢和互联网品脱,一如既往:)

编辑——我想我也会包含内联代码:

class ArchivesDropdownView extends Backbone.View
  template: '<select><option>One</option><option>Two</option></select>'
  initialize: () ->
    console.log 'Initialised the select dropdown'
  render: () ->
    this.$el.find('#dropdown').empty().append @template
    console.log 'Rendered the select dropdown'
    return this
  events:
    'change select': 'updateSelect'
  updateSelect: () ->
    console.log 'Updated select dropdown.'
    wrapperView.render()


class WrapperView extends Backbone.View
  template: 'Please select: <div id="dropdown"></div><div id="random"><%=randomNum%></div>'
  render: () ->
    console.log 'Rendered the wrapper'

    this.$el.empty().append _.template(@template)(randomNum: Math.random())

    if !this.archivesDropdownView
      this.archivesDropdownView = (new ArchivesDropdownView().render())

    this.archivesDropdownView.render()

    return this


wrapperView = new WrapperView()
$('body').empty().append wrapperView.render().$el

【问题讨论】:

    标签: javascript jquery backbone.js coffeescript


    【解决方案1】:

    在将视图$el 应用到另一个视图之后添加this.archivesDropdownView.delegateEvents()。

      this.$el.find('#dropdown').empty().append this.archivesDropdownView.$el
      this.archivesDropdownView.delegateEvents()
    

    但我不喜欢你的架构,你应该使用子视图的全局引用来渲染父视图。改用事件,例如在父视图和子视图之间共享模型,并从子视图触发事件以重新渲染父视图。

    这是一个工作示例http://jsbin.com/dehujecejape/1/edit

    【讨论】:

    • 这样就行了,谢谢。是的,我知道它的架构很糟糕,但是该代码是项目中非常非常旧的代码的精简版本-其余代码(和较新的项目)的结构要好得多,但我没有没有时间将这个项目完全重构为所有使用模型等 :(delegateEvents 目前运行良好,再次欢呼。
    • 我通过添加指向良好架构的链接来更新我的答案,该架构在子视图中有delegateEvents
    • 为更新干杯!每次更改值时,您的新版本都会呈现 ArchivesDropdownView;最初的问题之一是我只想渲染一次子视图,然后在重新渲染父视图时附加缓存的 view.$el。这是因为在现实世界的版本中,我选择在渲染时在选择框上运行,并且每次渲染自身时都会导致无样式选择元素的一种“闪烁”。也许这表明我的架构比我想象的更糟糕;)
    • 同样,重新渲染意味着选择框失去了它的状态,即它当前选择的选项。这在实际应用程序中无关紧要,因为我正在从其他地方加载选定的值,但这只是一个想法。我已将您的版本与模型一起使用,它很有效,非常感谢,但每当我重新渲染视图时,它仍然会产生短暂的闪光...... :(
    • 然后使用 2 个单独的(不是父子)视图并监听共享模型事件以在更改选择视图上重新渲染值视图。
    【解决方案2】:

    您遇到这种问题是因为您没有按照应有的方式做事。当其中一个组件发生变化时,为什么要重新渲染整个容器?当然,这种方法你会遇到各种各样的麻烦。

    我建议您创建第三个组件,并在选择框更改时对其进行更新:

    class ArchivesDropdownView extends Backbone.View      
      template: '<select><option>One</option><option>Two</option></select>'
      initialize: (opts)->
        console.log 'Initialised the select dropdown'    
        @listener = opts.listener
      render: ->
        console.log 'Rendered the select dropdown'
        @$el.html @template    
      events:
        'change': 'updateSelect'
      updateSelect: ->
        @listener.render()
    
    class RandomGeneratorView extends Backbone.View
      template: '<%=randomNum%>'
      render: ->
        @$el.html _.template(@template)(randomNum: Math.random())    
    
    class WrapperView extends Backbone.View
      template: 'Please select: <div id="dropdown"></div><div id="random"></div>'
      initialize: ->
        console.log "wrapper init"
        randomElement = new RandomGeneratorView()
        @randomGeneratorView = randomElement.render()
        @archivesDropdownView = (new ArchivesDropdownView(listener: randomElement)).render()
    
      render: ->
        @$el.html @template  
        @randomContainer = @$el.find "#random"
        @dropdownContainer = @$el.find "#dropdown"
        @dropdownContainer.html @archivesDropdownView
        @randomContainer.html @randomGeneratorView
        @$el
    
    $('body').html (new WrapperView()).render()
    

    这是modified JSBin

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-11-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多