this.model.on更改事件未触发

时间:2017-05-24 22:42:19

标签: javascript backbone.js backbone-events backbone-model

以下代码中未触发“更改”事件。

var PageView = Backbone.View.extend({
    el: $("body"),
    initialize: function(){
        this.model.on("change:loading", this.loader, this);
    },
    loader: function(){
        if(this.model.get("loading")){
            this.$el.find('.loader').fadeIn(700);
        }
        else 
            this.$el.find('.loader').fadeOut(700);
    },
});

var PageModel = Backbone.Model.extend({
    defaults: {
        loading: null,
    },
    initialize: function(){
        this.set({loading:false});
    },
});

$(function(){
    var pageModel = new PageModel({});
    var pageView = new PageView({model: pageModel});
})

如果我在模型的initialize函数中添加它,它会起作用:

 setTimeout(function() {
     this.set({'loading': 'false'});
 }, 0);

我可以这样离开,但这是一个错误。

1 个答案:

答案 0 :(得分:2)

解释的情况

这是代码运行的顺序:

  1. 创建模型,
  2. 调用模型的initialize函数,将loading属性设置为false
  3. 然后将模型传递给视图,
  4. 然后为"change:loading"
  5. 注册了一个监听器

    永远不会调用事件处理程序,因为事件在注册后永远不会发生。

    快速修复

    首先从模型中删除集合。

    var PageModel = Backbone.Model.extend({
        defaults: {
            loading: null
        }
    });
    

    然后,在创建视图后,设置loading属性。

    var pageModel = new PageModel();
    var pageView = new PageView({ model: pageModel });
    
    pageModel.set('loading', false); // now the event should trigger
    

    由于在模型的loading属性发生更改之前现在已注册了侦听器,因此将调用事件处理程序。

    优化解决方案

    使用Backbone的最佳做法:

    视图是一个原子组件,应该只关心自身及其子视图。

    虽然在您的情况下,在视图上使用el属性并不重要,但它仍然超出了视图的职责范围。让调用代码处理传递元素以用于此视图。

    var PageView = Backbone.View.extend({
        initialize: function() {
            this.model = new PageModel();
            this.$loader = this.$('.loader');
            this.listenTo(this.model, "change:loading", this.loader);
        },
        loader: function() {
            this.$loader[this.model.get("loading")? 'fadeIn': 'fadeOut'](700);
        },
        render: function() {
            this.loader();
            return this;
        }
    });
    

    将默认值放在它们所属的位置。

    var PageModel = Backbone.Model.extend({
        defaults: {
            loading: false
        }
    });
    

    我们选择body作为要用于视图的元素,使用el选项,然后在准备好时调用render

    $(function() {
        var pageView = new PageView({ el: 'body' }).render();
    });
    

    事件不会立即由侦听器触发,而是使用render函数将视图置于其默认状态。然后,loading属性的任何后续更改都将触发回调。

    我在个人资料页面上列出了most useful answers I've written about Backbone。您应该看看,它从开始到高级,甚至提供了一些聪明的Backbone组件,可以解决常见问题(例如在视图外部检测 )。