45

在我的简单项目中,我有 2 个视图 - 行项目视图(品牌)和应用程序。我附加了允许选择多个项目的功能:

var BrandView = Backbone.View.extend({
...一些代码...
    切换选择:函数(){
        this.model.selected = !this.model.selected;
        if(this.model.selected) $(this.el).addClass('selected');
        否则 $(this.el).removeClass('selected');
        返回这个;
    }
});

var AppView = Backbone.View.extend({
...一些代码...
    删除选择:函数(){
        _.each(Brands.selected(), function(model){
            模型.delete_selected();
        });
        返回假;
    },
});

问题是,我想知道选择了多少项目。在此设置中,选择不会影响模型,因此不会触发任何事件。从 MVC 概念中我了解到视图不应该直接与其他视图对话。那么 AppView 怎么知道 BrandViews 中选择了某些东西呢?

更具体地说,我 AppView 知道选择了多少项目,所以如果选择了超过 1 个,我会显示一个用于多选的菜单。

4

7 回答 7

74

您可能想阅读有关 Backbone pub/sub 事件的讨论:

http://lostechies.com/derickbailey/2011/07/19/references-routing-and-the-event-aggregator-coordinating-views-in-backbone-js/

我喜欢将其添加为全局事件机制:

Backbone.pubSub = _.extend({}, Backbone.Events);

然后在一个视图中,您可以触发一个事件:

Backbone.pubSub.trigger('my-event', payload);

在另一个你可以听:

Backbone.pubSub.on('my-event', this.onMyEvent, this);
于 2012-04-03T09:59:00.907 回答
7

我使用 Addy Osmani 所说的中介模式http://addyosmani.com/largescalejavascript/#mediatorpattern。整篇文章非常值得一读。

基本上它是一个事件管理器,允许您订阅和发布事件。因此,您的 AppView 将下标一个事件,即“选定”。然后 BrandView 将发布“选定”事件。

我喜欢这个的原因是它允许您在视图之间发送事件,而无需将视图直接绑定在一起。

例如

var mediator = new Mediator(); //LOOK AT THE LINK FOR IMPLEMENTATION

var BrandView = Backbone.View.extend({
    toggle_select: function() {
        ...
        mediator.publish('selected', any, data, you, want);
        return this;
    }
});

var AppView = Backbone.View.extend({
    initialize: function() {
        mediator.subscribe('selected', this.delete_selected)
    },

    delete_selected: function(any, data, you, want) {
        ... do something ...
    },
});

这样,您的应用程序视图不关心它是发布“选定”事件的 BrandView 还是 FooView,只关心事件发生了。因此,我发现它是一种可维护的方式来管理应用程序各部分之间的事件,而不仅仅是视图。

如果您进一步了解“外观”,您可以创建一个很好的权限结构。这将允许您说只有“AppView”可以订阅我的“选定”事件。我发现这很有帮助,因为它非常清楚事件的使用位置。

于 2012-04-02T23:02:23.053 回答
1

忽略您在帖子中已经提到的问题,您可以绑定和触发事件到/来自全局 Backbone.Event 对象,这将允许任何东西与其他任何东西对话。绝对不是最好的解决方案,如果你有意见互相聊天,那么你应该考虑重构它。但是你去吧!希望这可以帮助。

于 2012-04-02T22:59:18.917 回答
1

这是我有类似需求的情况:Backbone listenTo 似乎是一个解决方案,可以重定向到登录页面以处理超时或未经过身份验证的请求。

我将事件处理程序添加到我的路由器并使其监听全局事件,例如:

Backbone.Router.extend({
    onNotAuthenticated:function(errMsg){
        var redirectView = new LoginView();
        redirectView.displayMessage(errMsg);
        this.loadView(redirectView);
    },
    initialize:function(){
        this.listenTo(Backbone,'auth:not-authenticated',this.onNotAuthenticated);  
    },
    .....
});

在我的 jquery ajax 错误处理程序中:

$(document).ajaxError(
    function(event, jqxhr, settings, thrownError){
        .......
        if(httpErrorHeaderValue==="some-value"){
             Backbone.trigger("auth:not-authenticated",errMsg);
        }
    });     
于 2014-08-28T05:58:10.443 回答
1

您可以使用 Backbone 对象作为事件总线。

这种方法稍微干净一些,但仍然依赖于 Global Backbone 对象

var view1 = Backbone.View.extend({

  _onEvent : function(){
    Backbone.trigger('customEvent');
  }

});


var view2 = Backbone.View.extend({

  initialize : function(){
    Backbone.on('customEvent', this._onCustomEvent, this);
  },

  _onCustomEvent : function(){
    // react to document edit.
  }

});
于 2015-09-17T08:06:19.110 回答
0

使用相同的模型对象。AppView 可以使用集合进行初始化,而 BrandView 可以使用该集合中的一个模型进行初始化。当分支对象的属性发生变化时,任何其他引用该模型的代码都可以读取它。

因此,让您拥有一些通过集合获取的品牌:

var brands = new Brands([]);
brands.fetch();

现在您为每个模型创建一个 AppView 和一组 BrandView。

var appView = new AppView({brands: brands});
var brandViews = brands.map(function(brand) {
  return new BrandView({brand: brand});
});

appView 和brandViews 现在都可以访问相同的模型对象,所以当你改变一个时:

brands.get(0).selected = true;

然后它在被引用它的视图访问时也会发生变化。

console.log(appView.brands.get(0).selected); // true
console.log(brandViews[0].brand.selected)    // true
于 2012-04-02T23:02:47.860 回答
0

正如 John 上面所建议的那样,Mediator Pattern 在这种情况下非常有效,因为 Addy Osmani 在Backbone basics中再次总结了这个问题。

使用简单而强大的Backbone.Mediator插件结束,并使我的 AMD View 模块无缝协同工作 =)

于 2012-09-05T04:04:45.780 回答