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

this.model.on change event not firing

"change" 事件未在以下代码中触发。

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. 模型已创建,
  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 的最佳实践:

  • Favor .listenTo over .on 避免内存泄漏

视图是一个原子组件,应该只关心它自己和它的子视图。

虽然在您的情况下,在视图上使用 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 组件来解决常见问题(例如检测点击 外部 视图)。