backbone.js - 正确关闭 Marionette 中的 View

标签 backbone.js view keyboard-shortcuts marionette regions

我有一个基于 Backbone.Marionette 构建的应用程序,其中有一个 CollectionView,它实例化了许多 CompositeView,从而呈现树结构。

我已通读 Zombie Views ( Bailey on Zombies ) 以及 View 和 Region 文档。然而,如果阅读时一切看起来都很简单,那么执行起来就完全是一个不同的问题了。

当我点击任何路线时,我的键盘快捷键最终会被多次触发。我找到了一个解决方法,但此解决方法会导致 View 中渲染更改的其他问题。

这是多次触发键盘快捷键的实际代码。在 Snippet A ,我添加了我能想到的任何关闭 View 的方法,尽管通常情况下,关闭 View 只需要 App.contentRegion.currentView.treeRegion.close()

showContentView: (tree) ->
  if @treeView?
    App.contentRegion.currentView.treeRegion.reset()
    App.contentRegion.currentView.treeRegion.close()
    @treeView.close()
    delete @treeView
  @treeView = new App.Note.TreeView(collection: tree)
  App.contentRegion.currentView.treeRegion.show @treeView

Snippet B ,下面修复了键盘快捷键问题。但是,它会导致额外创建的模型 (CompositeView) 未呈现给用户的问题。

showContentView: (tree) ->
  if @treeView?
    @treeView.collection = tree
    @treeView.render()
  else
    @treeView = new App.Note.TreeView(collection: tree)
    App.contentRegion.currentView.treeRegion.show @treeView

这里是我初始化 CollectionView 的地方,它又渲染 CompositeViews

initialize: -> # collectionView
  @listenTo @collection, "sort", @render
  @listenTo @collection, "destroy", @addDefaultNote
  Note.eventManager.on 'createNote', @createNote, this
  Note.eventManager.on 'change', @dispatchFunction, this
  @drag = undefined

initialize: -> # compositeView
  @collection = @model.descendants
  @bindKeyboardShortcuts()
  @listenTo @collection, "sort", @render
  Note.eventManager.on "setCursor:#{@model.get('guid')}", @setCursor, @
  Note.eventManager.on "render:#{@model.get('guid')}", @render, @
  Note.eventManager.on "setTitle:#{@model.get('guid')}", @setNoteTitle, @

这就是我在 CompositeViews 中绑定(bind)键盘快捷键的方式

bindKeyboardShortcuts: ->
  @.$el.on 'keydown', null, 'ctrl+shift+backspace', @triggerShortcut 'deleteNote'
  @.$el.on 'keydown', null, 'tab', @triggerShortcut 'tabNote'
  @.$el.on 'keydown', null, 'shift+tab', @triggerShortcut 'unTabNote'
  @.$el.on 'keydown', null, 'alt+right', @triggerShortcut 'tabNote'
  @.$el.on 'keydown', null, 'alt+left', @triggerShortcut 'unTabNote'
  @.$el.on 'keydown', null, 'alt+up', @triggerShortcut 'jumpPositionUp'
  @.$el.on 'keydown', null, 'alt+down', @triggerShortcut 'jumpPositionDown'
  @.$el.on 'keydown', null, 'up', @triggerShortcut 'jumpFocusUp'
  @.$el.on 'keydown', null, 'down', @triggerShortcut 'jumpFocusDown'
  @.$el.on 'keydown', null, 'alt+ctrl+left', @triggerShortcut 'zoomOut'
  @.$el.on 'keydown', null, 'alt+ctrl+right', @triggerShortcut 'zoomIn'

以及我如何触发它们

triggerShortcut: (event) -> (e) =>
  e.preventDefault()
  e.stopPropagation()
  @triggerEvent(event).apply(@, Note.sliceArgs arguments)
triggerEvent: (event) ->
  (e) =>
    @updateNote()
    args = ['change', event, @model].concat(Note.sliceArgs arguments, 0)
    Note.eventManager.trigger.apply(Note.eventManager, args)

最后,为了确保一切都干净,我在 onBeforeClose 中取消绑定(bind)每个快捷方式。我还取消绑定(bind)任何 eventManager 的监听器。

onBeforeClose: ->
  console.log "view being closed", @
  @$el.off()
  Note.eventManager.off "setCursor:#{@model.get('guid')}"
  Note.eventManager.off "render:#{@model.get('guid')}"
  Note.eventManager.off "setTitle:#{@model.get('guid')}"
  Note.eventManager.off "timeoutUpdate:#{@model.get('guid')}"

我知道问题来自@treeView = new App.Note.TreeView(collection: tree) 。如果我在每个 @showContentView 上创建一个 TreeView (片段 A),每个添加的模型都正确渲染到 View 中,但快捷方式变得疯狂。
另一方面,如果我创建一个 TreeView 并交换它的集合(片段 B),我会在 View 中遇到渲染问题,但快捷方式没问题!

我试图包含您需要的所有内容,仅此而已(它已经是相当多的代码了..),但如果你们需要其他任何东西,请询问!
希望我能说得足够清楚..

[编辑] 我尝试了许多不同的组合来消除快捷方式错误,但如果我在每个 showContentView 上创建一个新的 TreeView,似乎没有任何方法可以正确关闭 View 。 我认为这是来自更深层次的内存泄漏问题。我可能会在这方面写另一个 StackOverflow 问题,并链接到此问题以获取更多信息。

非常感谢!

最佳答案

我弄清楚了这里的问题是什么。

使用 Snippet A 和 chrome devtool 的分析器,我可以追踪泄漏。我在问题中提供的 onClose 方法来自 CompositeView,其中绑定(bind)了键盘快捷键。
问题是 CollectionView 没有得到垃圾收集,因为使用了 Note.eventManager.on,它保留了对 View 的引用。 所以我给TreeView(CollectionView)添加了一个onBeforeClose方法

onBeforeClose: ->
  Note.eventManager.off('createNote', @createNote, this)
  Note.eventManager.off('change', @dispatchFunction, this)
  @drag = undefined

通过此 onBeforeClose, View 现在已正确关闭,这反过来又允许 subview 也关闭并停止监听正在触发的快捷方式。

我想这是非常明显的,一旦我发现,但我想添加这个答案,以便它清楚地表明您在没有 @listenTo 的情况下设置的任何事件监听器不会被 Marionette 清除,并且需要正确处理.

[编辑]

为了跟进评论,这从一开始就是一个更好的解决方案:

替换

initialize: -> # compositeView
  /* ... */
  Note.eventManager.on "setCursor:#{@model.get('guid')}", @setCursor, @
  Note.eventManager.on "render:#{@model.get('guid')}", @render, @
  Note.eventManager.on "setTitle:#{@model.get('guid')}", @setNoteTitle, @

initialize: -> # collectionView
  /* ... */
  Note.eventManager.on 'createNote', @createNote, this
  Note.eventManager.on 'change', @dispatchFunction, this

initialize: -> # compositeView
  /* ... */
  @listenTo Note.eventManager, "setCursor:#{@model.get('guid')}", @setCursor
  @listenTo Note.eventManager, "render:#{@model.get('guid')}", @render
  @listenTo Note.eventManager, "setTitle:#{@model.get('guid')}", @setNoteTitle

/* ... */

initialize: -> # collectionView
  /* ... */
  @listenTo Note.eventManager, 'createNote', @createNote, this
  @listenTo Note.eventManager, 'change', @dispatchFunction, this

像这样使用listenTo语法本来可以防止内存泄漏。 这样,onBeforeClose block 就可以完全删除了!

关于backbone.js - 正确关闭 Marionette 中的 View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19989626/

相关文章:

打开文档项列表的 Xcode 快捷方式

visual-studio-2012 - Ctrl + Dot (ShowSmartTag) 在 Visual Studio 2012 中不起作用

javascript - Backbone 集合长度与大小()

javascript - 如何使用 ChartJS 创建堆叠图

sql - 我的 Oracle View 使用了一个不存在的表,但我仍然可以查询它

java - Vaadin 中的 ENTER 快捷方式和 TextArea

javascript - Phantom.js 是否捕获所有 AJAX?

jquery - Backbone.js 和 Jquery 之间的区别

zend-framework - Zend 框架 1 : Different Error-Layout and -scripts for each module

python - Webpy,从另一个方法调用 View