Backbone JS:可以在其他视图中触发更新吗?

在我的简单项目中,我有2个视图 – 订单项视图(品牌)和应用程序。 我附加了允许select多个项目的function:

 var BrandView = Backbone.View.extend({
一些代码
     toggle_select:function(){
         this.model.selected =!this.model.selected;
         if(this.model.selected)$(this.el).addClass('selected');
         else $(this.el).removeClass('selected');
        返回这个;
     }
 });

 var AppView = Backbone.View.extend({
一些代码
     delete_selected:function(){
         _.each(Brands.selected(),function(model){ 
             model.delete_selected();
         });
        返回false;
     },
 });

事情是,我想知道有多less项目被选中。 在这个设置中,select不会影响模型,因此不会触发任何事件。 从MVC的概念我明白,意见不应该直接与其他意见交谈。 那么AppView如何知道在BrandView中select了什么?

更具体地说,我AppView知道有多less项目被选中,所以如果select多于1,我会显示一个多选的菜单。

您可能需要阅读关于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); 

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

基本上它是一个事件pipe理器,允许你订阅和发布事件。 所以你的AppView会下标到一个事件,即“select”。 然后,BrandView将发布“select”事件。

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

例如

 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,而只是发生该事件。 因此,我发现它是一种可pipe理的方式来pipe理你的应用程序之间的事件,而不仅仅是视图。

如果你进一步阅读“Facade”,你可以创build一个很好的权限结构。 这可以让你说只有一个“AppView”可以订阅我的“选定”事件。 我觉得这很有帮助,因为它清楚了事件在哪里使用。

忽略你已经在你的文章中提到的问题,你可以绑定和触发全局Backbone.Event对象的事件,这将允许任何事情与其他任何事情。 绝对不是最好的解决scheme,如果你有意见聊天,那么你应该考虑重构。 但是,你去! 希望这可以帮助。

这里是我的情况与类似的需求:骨干listenTo似乎是一个解决schemeredirect到login页面超时或未经过身份validation的请求。

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

 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的AJAXerror handling程序:

 $(document).ajaxError( function(event, jqxhr, settings, thrownError){ ....... if(httpErrorHeaderValue==="some-value"){ Backbone.trigger("auth:not-authenticated",errMsg); } }); 

您可以使用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. } }); 

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

所以,让我们让你有一些品牌,你通过集合获取:

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

现在你创build一个AppView,并为每个模型创build一个BrandView的数组。

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

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

 brands.get(0).selected = true; 

然后当它被引用的视图访问时它也会改变。

 console.log(appView.brands.get(0).selected); // true console.log(brandViews[0].brand.selected) // true 

和John上面提出的一样,Mediator Pattern在这种情况下工作得很好,正如Addy Osmani在Backbone基础中再次总结这个问题一样。

使用Backbone.Mediator插件创build简单而优秀的插件,使我的AMD视图模块无缝协作=)