Backbone不会触发'更改'模型上的事件,当我们设置更新的对象时。看this code
var MyModel = Backbone.Model.extend({
defaults: {
x: {}
}
});
var myModel = new MyModel();
myModel.on('change', function() { console.log('Changed'); });
var x = myModel.get('x');
x.something = 5; // Update the object
myModel.set('x', x); // Set the object. Does not trigger change event
Backbone Model已经存储了一个引用' x'对象{}。当我们更新对象并将对象再次设置到模型中时,引用仍然是相同的因此它不会触发更改事件。
其中一种方法是在设置模型之前克隆对象。看this code
var MyModel = Backbone.Model.extend({
defaults: {
x: {}
}
});
var myModel = new MyModel();
myModel.on('change', function() { console.log('Changed'); });
var x2 = _.clone(myModel.get('x'));
x2.something = 6;
myModel.set('x', x2);
问:这个问题有更好的方法吗?我不确定我是否做得对。
答案 0 :(得分:1)
这很棘手。由于您已经提到的原因,默认情况下您不能这样做。
您获得的对象与您稍后设置的对象相同。因此,它不仅不会检测到更改事件,还会在执行x.something = 5;
时更改模型中的数据而不会意识到这一点。
情况甚至更糟:
var MyModel = Backbone.Model.extend({
defaults: {
x: {}
}
});
var myModel = new MyModel();
var myModel2 = new MyModel();
var x = myModel.get('x');
x.something = 5;
console.log(myModel2.get('x'));
>> { something: 5 }
x的默认值将在所有实例之间共享,因为它是原型的一部分,被复制到实例并仍然引用原型的同一对象。 所以基本上,除了布尔值,数字和字符串之外,你不能使用默认值,并且你不能在任何其他类型上获得任何更改事件,除非你在变异或传入新的唯一对象之前克隆它们。
Backbone在其属性中的非平面数据结构中确实无法正常工作。
您的解决方案是其中一种可能性,但我可能会扩展基础Backbone.Model
并将_.clone
调用放入get
方法。
var DeepModel = Backbone.Model.extend({
get: function (attr) {
return _.clone(Backbone.Model.prototype.get.apply(this, arguments));
}
});
var myModel = new DeepModel({
x: {
something: 5
}
});
myModel.on('change', console.log.bind(console, 'Changed'));
var x = myModel.get('x');
x.something = 10;
myModel.set('x', x);
然后,您还可以覆盖set方法以触发更精确的事件,以便您还可以查看确切更改的字段。
知道change:x
会有点无用。
当然其他人也有同样的问题。 我知道至少有两个图书馆试图解决这类问题:
Backbone Relational
和backbone-deep-model
Backbone Relational非常重,因此在模型上处理非平面属性可能不是真正的选择。 我从未使用过骨干深度模型。只需检查一下,看看它是否适合您的使用案例。 我打赌还有其他库可以解决这个问题。 或者只是想出解决这个问题的方法并开源解决方案。