Backbone Collection 模型自我复制
Backbone Collection model duplicate itself
所以,我有一个 table 视图 (parent) 和 行视图 (child).
我用这段代码添加每一行
addOne: function (model, base) {
var view = new App.Views.file_manager_item({model: model});
base.append(view.render());
},
renderList: function () {
var _this = this;
var collection = this.files_collection;
document.getElementById("content").innerHTML = this.templates.table(this.context);
this.$files = $(document.getElementById('files'));
collection.each(function(model) {
_this.addOne(model, _this.$files);
});
},
renderList
被解雇:
this.listenTo(this.files_collection, "change", this.renderList);
App.Views.file_manager_item
是
var File_manager_item = Backbone.View.extend({
tagName: 'tr',
initialize: function () {
this.listenTo(this.model, "change", this.render);
},
template: Template7.compile(document.getElementById("fm_item_template").innerHTML),
events: {
"click .check": "toggleCheck",
},
toggleCheck: function () {
this.test = !this.test;
this.model.set({
"checked": this.test
});
},
render: function () {
console.log(this.model)
var context = this.model.toJSON();
this.el.innerHTML = this.template(context);
return this.$el;
},
});
和第一个 运行 return 控制台
child {cid: "c3", attributes: Object, ...}
...
...
...
...
child {cid: "c11", attributes: Object, ...}
在 toggleCheck
函数 运行s 两次之后
child {cid: "c3", attributes: Object, ...}
child {cid: "c3", attributes: Object, ...}
...
...
...
...
child {cid: "c11", attributes: Object, ...}
并且在每次模型更改后,在控制台
中添加新的child
child {cid: "c3", attributes: Object, ...}
为什么模型会重复?
模型并没有增加,只是视图仍然存在,即使不再出现在页面上。这是一种内存泄漏。同一个模型有多个项目视图,都在监听它的 change
事件。
避免这些泄漏的一个好方法是在创建项目视图时保留对项目视图的引用,然后在重新呈现之前对所有视图调用 .remove()
。
您的项目视图
var File_manager_item = Backbone.View.extend({
tagName: 'tr',
template: Template7.compile(document.getElementById("fm_item_template").innerHTML),
events: {
"click .check": "toggleCheck",
},
initialize: function() {
this.listenTo(this.model, "change", this.render);
},
toggleCheck: function() {
this.test = !this.test;
this.model.set({ "checked": this.test });
},
render: function() {
console.log(this.model);
// use jQuery because it's already available
this.$el.html(this.template(this.model.toJSON()));
return this; // return this to chain calls
},
});
然后列表视图
var ListView = Backbone.View.extend({
initialize: function() {
this.childViews = [];
this.listenTo(this.files_collection, "change", this.renderList);
},
addOne: function(model) {
var view = new App.Views.file_manager_item({ model: model });
this.childViews.push(view);
// this.$files is available here, there's no need to pass it around
this.$files.append(view.render().el);
},
renderList: function() {
// same thing, use jQuery, it's useless to use the native API to them put it
// into a jQuery object, unless a marginal performance gain is the goal.
this.$("#content").html(this.templates.table(this.context));
this.$files = this.$('#files');
this.cleanup();
// collection's each function is just a proxy to the underscore one.
this.files_collection.each(this.addOne, this); // use the context argument
return this;
},
cleanup: function() {
_.invoke(this.childViews, 'remove');
this.childViews = [];
},
});
所以,我有一个 table 视图 (parent) 和 行视图 (child).
我用这段代码添加每一行
addOne: function (model, base) {
var view = new App.Views.file_manager_item({model: model});
base.append(view.render());
},
renderList: function () {
var _this = this;
var collection = this.files_collection;
document.getElementById("content").innerHTML = this.templates.table(this.context);
this.$files = $(document.getElementById('files'));
collection.each(function(model) {
_this.addOne(model, _this.$files);
});
},
renderList
被解雇:
this.listenTo(this.files_collection, "change", this.renderList);
App.Views.file_manager_item
是
var File_manager_item = Backbone.View.extend({
tagName: 'tr',
initialize: function () {
this.listenTo(this.model, "change", this.render);
},
template: Template7.compile(document.getElementById("fm_item_template").innerHTML),
events: {
"click .check": "toggleCheck",
},
toggleCheck: function () {
this.test = !this.test;
this.model.set({
"checked": this.test
});
},
render: function () {
console.log(this.model)
var context = this.model.toJSON();
this.el.innerHTML = this.template(context);
return this.$el;
},
});
和第一个 运行 return 控制台
child {cid: "c3", attributes: Object, ...}
...
...
...
...
child {cid: "c11", attributes: Object, ...}
在 toggleCheck
函数 运行s 两次之后
child {cid: "c3", attributes: Object, ...}
child {cid: "c3", attributes: Object, ...}
...
...
...
...
child {cid: "c11", attributes: Object, ...}
并且在每次模型更改后,在控制台
中添加新的childchild {cid: "c3", attributes: Object, ...}
为什么模型会重复?
模型并没有增加,只是视图仍然存在,即使不再出现在页面上。这是一种内存泄漏。同一个模型有多个项目视图,都在监听它的 change
事件。
避免这些泄漏的一个好方法是在创建项目视图时保留对项目视图的引用,然后在重新呈现之前对所有视图调用 .remove()
。
您的项目视图
var File_manager_item = Backbone.View.extend({
tagName: 'tr',
template: Template7.compile(document.getElementById("fm_item_template").innerHTML),
events: {
"click .check": "toggleCheck",
},
initialize: function() {
this.listenTo(this.model, "change", this.render);
},
toggleCheck: function() {
this.test = !this.test;
this.model.set({ "checked": this.test });
},
render: function() {
console.log(this.model);
// use jQuery because it's already available
this.$el.html(this.template(this.model.toJSON()));
return this; // return this to chain calls
},
});
然后列表视图
var ListView = Backbone.View.extend({
initialize: function() {
this.childViews = [];
this.listenTo(this.files_collection, "change", this.renderList);
},
addOne: function(model) {
var view = new App.Views.file_manager_item({ model: model });
this.childViews.push(view);
// this.$files is available here, there's no need to pass it around
this.$files.append(view.render().el);
},
renderList: function() {
// same thing, use jQuery, it's useless to use the native API to them put it
// into a jQuery object, unless a marginal performance gain is the goal.
this.$("#content").html(this.templates.table(this.context));
this.$files = this.$('#files');
this.cleanup();
// collection's each function is just a proxy to the underscore one.
this.files_collection.each(this.addOne, this); // use the context argument
return this;
},
cleanup: function() {
_.invoke(this.childViews, 'remove');
this.childViews = [];
},
});