在 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 确实没有一个干净的方法来完成所需的操作,因此您最终将自己编写一些代码。
我认为更好的选择是使用新数据(collection
、model
、其他实例数据或任何合适的数据)重用现有视图实例。
当您更改页面的子视图时,您可能会传递一些变量,比如获取的 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 当然,我只是以此为例。
我正在 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 确实没有一个干净的方法来完成所需的操作,因此您最终将自己编写一些代码。
我认为更好的选择是使用新数据(collection
、model
、其他实例数据或任何合适的数据)重用现有视图实例。
当您更改页面的子视图时,您可能会传递一些变量,比如获取的 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 当然,我只是以此为例。