Backbone listenTo 不会因 属性 更改而触发

Backbone listenTo does not fire for property change

我是 Backbone 的新手,我有一些代码可以监听 属性 的变化并触发一个函数。我在网上看到的关于如何使用 listenTo 的所有内容似乎都涵盖了这种情况,所以我不知道我忽略了什么。

为了更好地理解我做了一个简单得多的示例,它只包含一个模型、一个视图和设置 listenTo。问题仍然出现在那个较小的样本中。

我已经放入了一些代码来记录正在触发哪些函数以及触发顺序。当我看到 运行 时,这段代码几乎是我期望的顺序,除了永远不会调用 onSomethingChanged。

var AppView = Backbone.View.extend({
    initialize: function(){
        this.listenTo(this.model, 'change:hasName', this.onSomethingChanged);

        $('#steps').append('<li>AppView initialize</li>');
        this.model.setName('Test Name');
    },
    onSomethingChanged: function(){
        $('#steps').append('<li>AppView onSomethingChanged</li>');
    }
});

var SomeModel = Backbone.Model.extend({
    initialize: function(){
        this.bind('change:name', this.onNameChanged, this);
        this.set({'name': 'Nothing'});

        $('#steps').append('<li>SomeModel initialize</li>');
    },
    onNameChanged: function(status, name){
        this.set({'hasName': name != null});

        $('#steps').append('<li>SomeModel onNameChanged</li>');
    },
    setName: function(name){
        this.set({'name': name});

        $('#steps').append('<li>SomeModel setName</li>');
    }
});

$(function(){
    window.app = new AppView({model: new SomeModel()});
});

我在此处的 fiddle 中进行了设置:https://jsfiddle.net/hamveefz,它显示的顺序如下:

  1. SomeModel onNameChanged
  2. SomeModel 初始化
  3. AppView 初始化
  4. SomeModel onNameChanged
  5. SomeModel setName

我假设在 SomeModel 的 onNameChanged 函数中,它随后对 hasName 属性 执行 'this.set' 会自动导致调用 hasName 更改的侦听器。

有人可以向我解释我哪里出错了吗?

调用 set 不一定会改变任何东西。例如,这个:

model.set('property', model.get('property'));

不会触发 'change' 事件,因为它实际上没有做任何事情。

您的模型的 initialize 设置名称:

this.set({'name': 'Nothing'});

'change:name' 处理程序受该点约束,因此 onNameChanged 将被调用并且 hasName 将设置为 true

然后构建视图,其 initialize 将:

this.listenTo(this.model, 'change:hasName', this.onSomethingChanged);
this.model.setName('Test Name');

您认为 setName 应该触发 'change:hasName' 事件,但它不会。 hasName 属性此时已经是 true 并且您将执行 set('hasName', true) 所以它不会改变。

您最好将 name 保留为 nullundefined,直到它真正被设置为止。您将从模型的 initialize 中删除 this.set({'name': 'Nothing'}); 并添加:

defaults: {
    name: null,
    hasName: false
}

然后调整视图(及其模板)来处理 "no name" 案例。