hac*_*ack 10 javascript backbone.js
我有一个带有大量模型的Backbone集合.
只要在模型上设置了特定属性并将其保存,就会触发大量计算并重新呈现UI.
但是,我希望能够同时在多个模型上设置属性,并且只有在设置完成后才进行保存和重新渲染.当然我不想为一个操作发出几个http请求,并且绝对不想要重新渲染接口十次.
我希望在Backbone.Collection上找到一个save方法,它可以解决哪些模型hasChanged(),将它们作为json重新组合并发送到后端.然后可以通过集合上的事件触发重新渲染.没有这样的运气.
这似乎是一个非常常见的要求,所以我想知道为什么Backbone没有实现.这是否违反RESTful架构,将多个内容保存到单个端点?如果是这样,那又怎样?让1000个小项继续生成1000个请求是不切实际的.
那么,唯一的解决方案是使用我自己的存储方法来扩充Backbone.Collection,该方法遍历其所有模型并为所有已更改并将其发送到后端的json构建?或者有没有人有一个更整洁的解决方案(或者我只是错过了一些东西!)?
我最终用几种方法来增强 Backbone.Collection 来处理这个问题。
saveChangeMethod 创建一个虚拟模型以传递给 Backbone.sync。模型中所有主干的同步方法需要的是它的 url 属性和 toJSON 方法,所以我们可以轻松地解决这个问题。
在内部,模型的 toJSON 方法仅返回其属性的副本(将发送到服务器),因此我们可以愉快地使用仅返回模型数组的 toJSON 方法。Backbone.sync 将其字符串化,这只为我们提供属性数据。
成功后,saveChanged 会触发要处理一次的集合上的事件。添加了一些代码,使其针对任何批次模型中已更改的每个属性触发一次特定事件。
Backbone.Collection.prototype.saveChanged = function () {
var me = this,
changed = me.getChanged(),
dummy = {
url: this.url,
toJSON: function () {
return changed.models;
}
},
options = {
success: function (model, resp, xhr) {
for (var i = 0; i < changed.models.length; i++) {
changed.models[i].chnageSilently();
}
for (var attr in changed.attributes) {
me.trigger("batchchange:" + attr);
}
me.trigger("batchsync", changed);
}
};
return Backbone.sync("update", dummy, options);
}
Run Code Online (Sandbox Code Playgroud)
然后我们只需要集合上的 getChanged() 方法。这将返回一个具有 2 个属性的对象,一个已更改模型的数组和一个标记哪些属性已更改的对象:
Backbone.Collection.prototype.getChanged = function () {
var models = [],
changedAttributes = {};
for (var i = 0; i < this.models.length; i++) {
if (this.models[i].hasChanged()) {
_.extend(changedAttributes, this.models[i].changedAttributes());
models.push(this.models[i]);
}
}
return models.length ? {models: models, attributes: changedAttributes} : null;
}
Run Code Online (Sandbox Code Playgroud)
尽管这稍微滥用了主干“更改模型”范例的预期用途,但批处理的全部要点是,当模型更改时,我们不希望发生任何事情(即触发任何事件)。
因此,我们必须将 {silent: true} 传递给模型的 set() 方法,因此使用骨干网的 hasChanged() 来标记等待保存的模型是有意义的。当然,如果您出于其他目的而默默地更改模型,这将是有问题的 - collection.saveChanged() 也会保存这些模型,因此值得考虑设置替代标志。
无论如何,如果我们这样做,在保存时,我们需要确保主干现在认为模型没有改变(不触发它们的更改事件),所以我们需要手动操作模型,就好像它没有改变一样被改变了。saveChanged() 方法迭代我们更改的模型,并在模型上调用这个 changeSilently() 方法,这基本上只是 Backbone 的 model.change() 方法,没有触发器:
Backbone.Model.prototype.changeSilently = function () {
var options = {},
changing = this._changing;
this._changing = true;
for (var attr in this._silent) this._pending[attr] = true;
this._silent = {};
if (changing) return this;
while (!_.isEmpty(this._pending)) {
this._pending = {};
for (var attr in this.changed) {
if (this._pending[attr] || this._silent[attr]) continue;
delete this.changed[attr];
}
this._previousAttributes = _.clone(this.attributes);
}
this._changing = false;
return this;
}
Run Code Online (Sandbox Code Playgroud)
用法:
model1.set({key: value}, {silent: true});
model2.set({key: value}, {silent: true});
model3.set({key: value}, {silent: true});
collection.saveChanged();
Run Code Online (Sandbox Code Playgroud)
关于。RESTful.. 对集合的端点执行 PUT 来更改其“某些”记录是不太正确的。从技术上讲,PUT 应该替换整个集合,但在我的应用程序实际上需要替换整个集合之前,我很乐意采取务实的方法。