在 Backbone 中多次初始化视图

Initializing a View multiple times in Backbone

我正在 Backbone 中构建一个网站,网站结构类似于 Youtube,因为当您使用页面上的 link 更改页面时,只有一部分 DOM(即非导航组件)被重新加载而不是整个文档。

因此,当用户使用我网站上的 link 访问子页面时,Backbone 将发出 AJAX 调用并接收子页面的 HTML,看起来像这样:

<section id="SubpageView">...</section>
<script>

// Defines the view that controls #SubpageView.
if(typeof SubpageView !== 'undefined') {

    // If this is the first time the page is loaded, create class.
    var SubpageView = Backbone.Model.extend({
        el: '#SubpageView',
        ...
    });

}

MainView.currentSubpage = new SubpageView();
</script>

多次调用 SubpageView() 是否有任何缺点(即僵尸视图、内存泄漏等)?在我看来,使用 el 而不是 tagName 来定义视图元素是针对只使用一次的元素。

注意: 我知道单页 Web 应用程序通常将所有模板都嵌入到持久性 DOM 中,并且所有 HTML 都是使用客户端模板处理。但是因为我正在设计网站以在没有 pushState() 或禁用 [​​=34=] 的情况下降级为传统的服务器端呈现,所以我不想将我的所有模板都烘焙到持久的 DOM.

这是一个很好的问题 - 我认为很多人都忽视了这个问题,它会导致问题。 "Zombie Views" 是一个很好的描述符。我会说你是对的,它们会引起问题:

  • 您正在维护不再需要的(可能很大的)对象实例。
  • 您的僵尸视图实例仍然可以引用仍在使用的现有对象,并可能导致意外行为。

如果您使用 Backbone 的事件哈希,最后一点尤为重要,例如:

events: {
    'click .someButton': 'someMethod',
    // ...
},

由于您正在重用 el 选择器(我认为您应该这样做),因此所有僵尸视图的事件将保持活动状态,并在它们不需要时触发视图的功能。这可能意味着重复行为,或其他完全意外的结果。


至于解决方案,我认为您有两种选择:一种是在更新之前销毁旧视图实例。默认的 remove 方法实际上删除了您不想要的 el... undelegateEvents 可能会有所帮助。 Backbone 确实没有一个干净的方法来完成所需的操作,因此您最终将自己编写一些代码。

我认为更好的选择是使用新数据(collectionmodel、其他实例数据或任何合适的数据)重用现有视图实例。

当您更改页面的子视图时,您可能会传递一些变量,比如获取的 html:

$.get('/templates/someView.html', function(html) {
    Mainview.currentSubpage = new SubpageView(html);
});

...或类似的东西。相反,我建议编写一个方法来更新现有实例,例如:

$.get('/templates/someView.html', function(html) {
    Mainview.currentSubpage.resetPage(html);
});

resetPage 方法写入 SubpageView 以完成您需要的工作。这不仅适用于 html 当然,我只是以此为例。