当我们设置更新的对象时,如何在主干模型上触发更改事件

How to trigger change event on Backbone model when we set an updated object

本文关键字:模型 事件 更新 设置 我们 对象      更新时间:2023-09-26

Backbone在设置更新对象时不会触发模型上的"更改"事件。看看这个代码

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

解决方案:

骨干模型存储了对对象{}的引用"x"。当我们更新对象并将对象重新设置到模型中时,引用仍然相同,因此不会触发更改事件。

其中一种方法是在设置到模型中之前克隆对象。看看这个代码

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);

问:有没有更好的方法来解决这个问题?我不确定我的做法是否正确

这很棘手。默认情况下,由于您已经提到的原因,您不能这样做。您取出的对象与您稍后设置的对象相同。因此,它不仅没有检测到更改事件,而且在执行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方法来触发更精确的事件,这样您也可以看到哪个字段发生了确切的更改。CCD_ 5可能有点没用。

当然,其他人也有同样的问题。据我所知,至少有两个图书馆试图解决这类问题:

骨干关系
和骨干深度模型

Backbone Relational相当重,因此仅处理模型上的非平面属性可能不是正确的选择。我从未使用过骨干深度模型。只要检查一下,看看它是否适合您的用例。我打赌还有其他库可以解决这个问题。或者只是想出你自己的方法来解决这个问题,并开源解决方案。