我注意到当Backbone模型的多个属性设置如此
时model.set({
att1:val1,
att2:val2
});
触发两个更改事件。我错误地假设在设置了所有属性之后只会触发一个更改事件。
这似乎不是一个问题,但是当一个函数绑定到att1时,它也使用了att2的值。换句话说,当你这样做时
model.bind('change:att1', func1);
...
func1 = function() {
var att2 = model.get('att2');
}
变量att2将设置为模型属性att2的旧值。
问题是如何以优雅的方式防止这种情况。当然,一个选项是在设置att1之前设置att2或绑定到att2(而不是att1),但似乎这只是在简单情况下可行的选项。后一个选项还假设属性是按照set方法中列出的顺序设置的(我认为是这种情况)。
我已多次遇到这个问题因此我的问题。问题是我花了一些时间才意识到实际发生了什么。
最后一点,就像你可以将{silent:true}作为set方法的一个选项一样,有一个选项{group:true}(或类似的东西)表示更改事件会很不错只有在设置了所有属性后才能触发。
答案 0 :(得分:7)
在更复杂的情况下,我会选择自定义活动。
而不是绑定到更改:att1或更改:att2我会查找特定的自定义事件,在设置了要在模型上更改的所有属性后触发。
model.set({
att1:val1,
att2:val2
});
model.trigger('contact:updated'); // you can chose your custom event name yourself
model.bind('contact:updated', func1);
...
func1 = function() {
var att2 = model.get('att2');
}
这个想法的缺点是你必须在想要触发事件的任何地方添加新的代码行。如果发生这种情况很多你可能想改变或覆盖model.set()来为你做,但是你已经在改变骨干代码,不知道你对此感觉如何。
修改强>
在查看主干的源代码后,我注意到在change
触发后立即触发了change:attribute
事件。 (由下面的snippit证明)
// Fire `change:attribute` events.
for (var attr in changes) {
if (!options.silent) this.trigger('change:' + attr, this, changes[attr], options);
}
// Fire the `"change"` event, if the model has been changed.
if (!alreadyChanging) {
if (!options.silent && this._changed) this.change(options);
this._changing = false;
}
而this.change(options);
指的是:
change: function(options) {
this.trigger('change', this, options);
this._previousAttributes = _.clone(this.attributes);
this._changed = false;
},
因此,如果您要绑定change
事件而不是特定的change:argument
事件,则在更改两个(或所有)属性后,您将到达回调函数。
唯一的缺点是,即使您更改了第三个或第四个属性,它也会触发任何更改。你需要在......中计算出来。
它在jsfiddle http://jsfiddle.net/saelfaer/qm8xY/
上的工作原理的一个小例子