我注意到当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}(或类似的东西)表示更改事件应该只是在设置了所有属性后触发.
解决方法
在更复杂的情况下,我会去自定义活动.
而不是绑定到更改: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()来为你做,但是你已经在改变骨干代码,不知道你对此感觉如何.
编辑
在查看了主干的源代码之后,我注意到在更改后立即触发了更改事件:属性触发器. (由下面的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(选项);指这个:
change: function(options) { this.trigger('change',options); this._prevIoUsAttributes = _.clone(this.attributes); this._changed = false; },
因此,如果您要绑定到更改事件而不是特定的change:argument事件,则在更改两个(或所有)属性后,您将到达回调函数.
唯一的缺点是,即使您更改了第三个或第四个属性,它也会触发任何更改.你需要计算…
它在jsfiddle http://jsfiddle.net/saelfaer/qm8xY/上如何工作的一个小例子