对于我的一个项目,我正在监听模型对象的属性更改,并在其属性发生变化时调用视图方法。
问题是我的模型的一个属性是一个momentjs日期对象。
我查看了主干来源,似乎它使用下划线方法_.isEqual()
触发了setter中的更改。
阅读underscore documentation后,isEqual
会对两个对象进行深入比较。
似乎没有问题,但是momentjs对象包含初始格式化信息,即使日期的实际值具有相同的含义,如果它来自不同的地方,它的格式可能不同,因此,通过下划线深度比较可以认为不相等
// initialize model
var today = moment().startOf('day');
var model = new Backbone.Model({
start: today
});
// change event
model.on('change', function(e){
// if property start has changed
if(e.changed.hasOwnProperty('start')){
// log it
console.log('date changed');
}
});
// simulates input from user
var userInput = moment().startOf('day').format('DD/MM/YYYY');
model.set({
// it's the same day as today and it shouldn't trigger a change !
start: moment(userInput,'DD/MM/YYYY')
});
我应该怎么做?
isEqual
什么时候它是一个对象?但我宁愿不修改下划线,修改momentjs似乎还不错。答案 0 :(得分:3)
您最好的选择是覆盖model.set
方法以对某些属性执行自定义相等检查。
让我们创建EqualModels
作为保存覆盖的基类:
var EqualModels = Backbone.Model.extend({
set: function(key, val, options) {
if (!this.equals)
return Backbone.Model.prototype.set.apply(this, arguments);
//lifted from Backbone source code
var attrs, attr, dropped, fn;
if (key == null) return this;
// Handle both `"key", value` and `{key: value}` -style arguments.
if (typeof key === 'object') {
attrs = key;
options = val;
} else {
(attrs = {})[key] = val;
}
options || (options = {});
//determine which attributes have a custom equality check and apply it
dropped = [];
for (attr in attrs) {
fn = this.equals[attr];
if (_.isFunction(fn)) {
if (fn(this.attributes[attr], attrs[attr]))
dropped.push(attr);
}
}
//remove the attributes that are deemed equal
attrs = _.omit(attrs, dropped);
return Backbone.Model.prototype.set.call(this, attrs, options);
}
});
目标是确定某个属性是否在this.equals
中定义了相等性检查,对当前值和潜在值应用此函数,如果认为值相等,则从集合属性中删除该属性。
然后您可以将模型写为
var M = EqualModels.extend({
equals: {
start: function(v1, v2) {
if (typeof(v1)!==typeof(v2)) return false;
return v1.format('DD/MM/YYYY')===v2.format('DD/MM/YYYY');
}
}
});
此处仅在 DD / MM / YYYY 格式不同时更新时刻对象。还有一个演示http://jsfiddle.net/Nwdf4/3/
答案 1 :(得分:0)
正如nikoshr所提到的那样,它不应该引起太大的关注,因为事件仅在您执行set或fetch时触发,并且在这两种情况下,您都可以使用{silent:true}选项使事件静音。因此,如果您控制可能对日期进行更新的位置,您可以在此处实现自己的比较方法,以确定它是否应该是静默的,这样,无需修改momentjs,下划线或模型。 / p>
话虽如此,我相信你的第一种方法实际上是'正确',因为在你的模型的值中拥有对象实例可能不是一个好主意,因为Backbone不会自动序列化它们。我觉得存储时间戳或包含模型和模型的parse()中所有相关信息的简单时间表示会更清晰,将其转换为MomentJs对象并将其存储在对象的属性中。这意味着它不能通过model.get('momentJsObject')获得,而是通过model.momentJsObject,你仍然可以使用get('rawMoment')访问源数据,准备序列化回服务器。当然,这实际上取决于具体情况,这只是一种“一般情况”的参考。