Backbone 幻像视图触发事件
Backbone events triggering on phantom views
场景
我继承了旧版 backbone 应用程序的主要细节场景。在主视图上,我有项目列表(项目),当我单击一个项目时,我可以在详细信息视图(ProjectFormView)上对其进行编辑。
问题
当我在 ProjectFormView 上编辑项目时,所有以前打开的项目也使用相同的值进行编辑。
详情:
我发现,输入更改等 UI 事件也会在之前打开的 ProjectFormViews 上触发,因此看起来像是某种内存泄漏。
视图是这样实例化的:
displayProject: function(appType, appId, projectId) {
if (this.applicationDetailsModel === undefined ||
this.applicationDetailsModel.get('formType') !== appType ||
this.applicationDetailsModel.get('id') !== appId)
{
this.navigateTo = 'projects';
this.navigateToItem = projectId;
this.navigate('form/' + appType + '/' + appId, { trigger: true });
return;
}
var that = this;
require(['views/projectFormView'], function(ProjectFormView) {
var tooltips = that.tooltipsCollection
.findWhere({ form: 'project' })
.get('fields');
if (that.isCurrentView(that.projectFormView, appId, appType) === false) {
that.projectFormView = new ProjectFormView({
el: $content,
tooltips: tooltips,
projectScale: that.projectScale,
workTypes: that.workTypes
});
}
that.projectFormView.listenToOnce(that.projectScale, 'sync', that.projectFormView.render);
that.projectFormView.listenToOnce(that.workTypes, 'sync', that.projectFormView.render);
that.renderItem(that.projectFormView, that.projectsCollection, projectId, 'projects');
that.highlightItem('projects');
});
},
还有风景。注意 SetValue
中的注释
return ApplicantFormView.extend({
events: {
'change #newProject input': 'processProject',
'change #newProject select': 'processProject',
'change #newProject textarea': 'processProject',
},
template: JST['app/scripts/templates/projectForm.hbs'],
initialize: function (options) {
this.projectScale = options.projectScale;
this.workTypes = options.workTypes;
this.tooltips = options.tooltips;
},
render: function () {
Backbone.Validation.bind(this, {
selector: 'id'
});
this.$el.html(this.template(
{
project: this.model.attributes,
projectScale: this.projectScale.toJSON(),
workTypes: this.workTypes.toJSON(),
appType: profileModel.get('loadedAppType'),
appId: profileModel.get('applicationId')
}
));
this.$('.datepicker').datepicker({
endDate: 'today',
minViewMode: 1,
todayBtn: 'linked',
orientation: 'top auto',
calendarWeeks: true,
toggleActive: true,
format: 'MM yyyy',
autoclose: true
});
this.$('.datepicker').parent().removeClass('has-error');
this.$('.error-msg').hide();
this.$el.updatePolyfill();
this.revalidation();
return this;
},
processProject: function (event) {
this.setValue(event);
this.save();
},
setValue: function (event) {
//This is called on each input change as many times as many projects were previously opened.
event.preventDefault();
var $el = $(event.target),
id,
value;
if ($el.attr('type') === 'checkbox') {
id = $el.attr('id');
value = $el.is(':checked');
} else if ($el.attr('type') === 'radio') {
id = $el.attr('name');
value = $('input:radio[name ="' + id + '"]:checked').val();
} else {
id = $el.attr('id');
value = $el.val();
}
this.model.set(id, value);
Dispatcher.trigger('upd');
},
});
您有什么提示可以导致内存泄漏吗?
似乎所有视图都附加到 $content
。每当您为此元素创建新视图时,都会将一组新的事件侦听器附加到此元素。
理想情况下,您应该在创建新视图之前删除现有视图,以使用视图的 remove
方法释放内存。
如果由于某种原因您不能这样做并且希望同时在内存中保留所有创建的视图对象,它们需要有自己的元素来绑定事件。
您可以通过删除 el: $content,
这让我们 backbone 为每个视图创建一个元素。
然后在创建视图后执行 $content.append(view.el)
。
创建新视图时,您必须从 $content
中分离这些元素。
场景
我继承了旧版 backbone 应用程序的主要细节场景。在主视图上,我有项目列表(项目),当我单击一个项目时,我可以在详细信息视图(ProjectFormView)上对其进行编辑。
问题
当我在 ProjectFormView 上编辑项目时,所有以前打开的项目也使用相同的值进行编辑。
详情:
我发现,输入更改等 UI 事件也会在之前打开的 ProjectFormViews 上触发,因此看起来像是某种内存泄漏。
视图是这样实例化的:
displayProject: function(appType, appId, projectId) {
if (this.applicationDetailsModel === undefined ||
this.applicationDetailsModel.get('formType') !== appType ||
this.applicationDetailsModel.get('id') !== appId)
{
this.navigateTo = 'projects';
this.navigateToItem = projectId;
this.navigate('form/' + appType + '/' + appId, { trigger: true });
return;
}
var that = this;
require(['views/projectFormView'], function(ProjectFormView) {
var tooltips = that.tooltipsCollection
.findWhere({ form: 'project' })
.get('fields');
if (that.isCurrentView(that.projectFormView, appId, appType) === false) {
that.projectFormView = new ProjectFormView({
el: $content,
tooltips: tooltips,
projectScale: that.projectScale,
workTypes: that.workTypes
});
}
that.projectFormView.listenToOnce(that.projectScale, 'sync', that.projectFormView.render);
that.projectFormView.listenToOnce(that.workTypes, 'sync', that.projectFormView.render);
that.renderItem(that.projectFormView, that.projectsCollection, projectId, 'projects');
that.highlightItem('projects');
});
},
还有风景。注意 SetValue
中的注释return ApplicantFormView.extend({
events: {
'change #newProject input': 'processProject',
'change #newProject select': 'processProject',
'change #newProject textarea': 'processProject',
},
template: JST['app/scripts/templates/projectForm.hbs'],
initialize: function (options) {
this.projectScale = options.projectScale;
this.workTypes = options.workTypes;
this.tooltips = options.tooltips;
},
render: function () {
Backbone.Validation.bind(this, {
selector: 'id'
});
this.$el.html(this.template(
{
project: this.model.attributes,
projectScale: this.projectScale.toJSON(),
workTypes: this.workTypes.toJSON(),
appType: profileModel.get('loadedAppType'),
appId: profileModel.get('applicationId')
}
));
this.$('.datepicker').datepicker({
endDate: 'today',
minViewMode: 1,
todayBtn: 'linked',
orientation: 'top auto',
calendarWeeks: true,
toggleActive: true,
format: 'MM yyyy',
autoclose: true
});
this.$('.datepicker').parent().removeClass('has-error');
this.$('.error-msg').hide();
this.$el.updatePolyfill();
this.revalidation();
return this;
},
processProject: function (event) {
this.setValue(event);
this.save();
},
setValue: function (event) {
//This is called on each input change as many times as many projects were previously opened.
event.preventDefault();
var $el = $(event.target),
id,
value;
if ($el.attr('type') === 'checkbox') {
id = $el.attr('id');
value = $el.is(':checked');
} else if ($el.attr('type') === 'radio') {
id = $el.attr('name');
value = $('input:radio[name ="' + id + '"]:checked').val();
} else {
id = $el.attr('id');
value = $el.val();
}
this.model.set(id, value);
Dispatcher.trigger('upd');
},
});
您有什么提示可以导致内存泄漏吗?
似乎所有视图都附加到 $content
。每当您为此元素创建新视图时,都会将一组新的事件侦听器附加到此元素。
理想情况下,您应该在创建新视图之前删除现有视图,以使用视图的 remove
方法释放内存。
如果由于某种原因您不能这样做并且希望同时在内存中保留所有创建的视图对象,它们需要有自己的元素来绑定事件。
您可以通过删除 el: $content,
这让我们 backbone 为每个视图创建一个元素。
然后在创建视图后执行 $content.append(view.el)
。
创建新视图时,您必须从 $content
中分离这些元素。