2011-10-13 78 views
35

我將我的視圖和路由器分隔成需要的單獨文件。然後我有一個main.js文件實例化路由器,並呈現我的默認視圖。使用Backbone.js路由器瀏覽通過require.js模塊化的視圖

我的路由器將視圖('查看/:id')和編輯('編輯/:id')作爲路由。在main.js中,當我實例化路由器時,我可以硬編碼router.navigate('View/1',true)並且導航工作正常。在我的視圖文件中,當我點擊編輯鏈接時,我想調用router.navigate('View /'+ id,true),但我不知道該怎麼做。

我已經成功調用Backbone.history.navigate('View /'+ id,true),但我不覺得我應該依賴全局Backbone對象。

我嘗試通過({路由器:appRouter})到我的意見,所以我可以使用this.options.router.navigate(),但是這不適合我。

如果你很好奇,這裏是從我的應用程序一串代碼:

路由器:

define(['./View', './Edit'], function (View, Edit) { 
    return Backbone.Router.extend({ 
     routes: { 
      'View/:id': 'view', 
      'Edit/:id': 'edit' 
     }, 

     view: function (id) { 
      var model = this.collection.get(id); 
      var view = new View({ model: model }); 
      view.render(); 
     }, 

     edit: function (id) { 
      var model = this.collection.get(id); 
      var edit = new Edit({ model: model }); 
      edit.render(); 
     } 
    }); 
}); 

查看:

define(function() { 
    return Backbone.View.extend({ 
     template: Handlebars.compile($('#template').html()), 

     events: { 
      'click .edit': 'edit' 
     }, 

     render: function() { 
      //Create and insert the cover letter view 
      $(this.el).html(this.template(this.model.toJSON())); 
      $('#View').html(this.el); 

      return this; 
     }, 

     edit: function() { 
      Backbone.history.navigate('Edit/' + this.model.id, true); 
     }, 
    }); 
}); 
+0

嗨,我正在做類似你的事情,打算在我的View模塊中使用router.navigate()。你是如何最終實現這一目標的? Thx非常提前。 – chaonextdoor

+4

我結束了使用Backgone.history.navigate。由於我將視圖分離爲視圖,路由器和模型的單個文件,並使用require.js加載它們。將路由器或事件對象傳遞給我的所有視圖太麻煩了。全球似乎是最有意義的,因爲骨幹已經在全球命名空間。 – MrGrigg

+1

so backbone.history.navigate等於router.navigate? – chaonextdoor

回答

20

與幾乎任何骨幹問題一樣,有很多方法可以解決這個問題。我走近它在我的當前項目的方式是把一切都放在一個全球性的自定義命名空間,並用它來繞過必需的引用:然後

var MyNamespace = {}; 

MyNamespace.init = function() { 
    MyNamespace.appView = new MyAppView(); 
    MyNamespace.router = new MyRouter(); 
    // etc 
} 

意見可以參考的必要MyNamespace.router。但它看起來像這樣將無法工作/不與require.js鼓勵,所以這裏有一些其他的選項:

  • 永遠不要叫路由器明確 - 相反,改變全局狀態對象路由器收聽。這實際上是我在當前項目中完成的工作 - 有關更多詳細信息,請參閱this response

  • 將路由器連接到頂層視圖(通常稱爲AppView),使其可以全局訪問,並使用AppView.router.navigate()

  • 創建另一個模塊,該模塊提供了一個內部調用Backbone.history.navigate()的實用函數navigate。這與你正在做的事情沒有什麼不同,但它會使它稍微更加模塊化,並且始終不讓你使用全局引用。這也允許您更改內部實現。

+0

您是否在需求模塊之外聲明瞭MyNamespace? 這是接近使用全局骨幹對象,只是用我自己的對象,對吧? – MrGrigg

+0

我沒有使用require.js,所以它不適用於我的情況。我認爲我列表中的最後一個項目可能是最接近require.js成語的。 – nrabinowitz

+0

是的,我自己調用導航的實用程序並不是一個壞主意。如果我這樣做,我可能會使相同的實用程序提供我的路由器作爲選項,也許這將解決整個事情。 – MrGrigg

8

你能做到這一點的老式方法with window.location.hash :)

window.location.hash = "Edit/1" 

如果您不需要明確的路線,這裏有一個備用解決方案。當你的應用程序啓動時創建的任何地方延伸主幹活動

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

然後在一個對象,你應用程式,您可以監聽事件

EventDispatcher.bind("mymodel:edit", this.editHandler, this); 

而且還從任何地方發出事件,data以下任何PARAMS你想要一起發送

EventDispatcher.trigger("mymodel:edit", data); 
+0

我嘗試使用window.location之前,我發現我可以使用全局Backbone對象,但它並沒有實際觸發我的事件,這可能是一個完全不同的問題。 – MrGrigg

+0

如果您只使用路由來觸發事件(您不需要url可見地更改,或者用戶使用後退/前進按鈕),那麼我今天下午想到的一些內容可能會有所幫助。您可以創建一個全球性的「EventDispatcher」,我將其添加到上面的答案中。 – kreek

+0

謝謝KreeK。我已經來回想要URL對於這個特定的應用程序很重要。我已經看到至少有一個類似於您的全局事件調度程序的其他示例。謝謝你的幫助。 – MrGrigg

32

如果其他人正在尋找像我這樣的問題的解決方案,我發佈了我最終做的事情。如果您使用樣板backbone.js,那麼您將在router.js中有initialize()函數。我修改了initialize()功能如下所示:

initialize = function() { 
    var app_router; 
    app_router = new AppRouter(); 

    // Extend the View class to include a navigation method goTo 
    Backbone.View.goTo = function (loc) { 
    app_router.navigate(loc, true); 
    }; 

    Backbone.history.start(); 
}; 

由於Backbone.js的的繼承的特別味道,這讓讓我打電話給MyView.goTo(location);從內我的任何意見。

+9

我不得不使用'Backbone.View.prototype.goTo =' –

+0

你可以在視圖中使用它,在成功回調中,或者你會怎麼做?這裏是我遇到的問題,如果你想看到我所指的代碼... http://stackoverflow.com/questions/19472777/clear-localstorage-and-change-the-view-backbone – Lion789

+0

非常優雅的解決方案!非常感謝。我已經使用了Backbone.View.prototype來實現另一個功能,但是這並不是我想到的。 – digaomatias

5

對我來說,與GOTO功能的解決方案有輕微的變化

Backbone.View.prototype.goTo = function (loc) { 
     appRouter.navigate(loc, true); 
    }; 
3

我知道這個問題是舊的工作,但我想知道你爲什麼不爲了得到路由器使用require.js :

define(['./PathToRouter', ], function (router) { 
    return Backbone.View.extend({ 
     template: Handlebars.compile($('#template').html()), 

     events: { 
      'click .edit': 'edit' 
     }, 

     render: function() { 
      //Create and insert the cover letter view 
      $(this.el).html(this.template(this.model.toJSON())); 
      $('#View').html(this.el); 

      return this; 
     }, 

     edit: function() { 
      router.navigate('Edit/' + this.model.id, true); 
     } 
    }); 
}); 
+0

我不知道爲什麼我沒有想到這個。我做過的大部分事情都沒有要求路線,所以我還沒有重新討論過這段時間。我很高興你插話。 – MrGrigg

+2

在上面的示例中,./PathToRouter不是路由器的實例,而是類定義。骨幹路由器唯一的靜態方法是無法導航! – LarZuK

+0

@LarZuK我很遠離這個問題,我甚至沒有想到,但你完全正確。 – MrGrigg

2

這種方法怎麼樣?作爲主幹在所有4個組件中實現了模板模式,通過一些設計,您可以通過應用程序的路由器爲每個視圖提供一個簡單的導航機制,而無需進行任何循環引用(這是我在其他類似帖子中看到的,但儘量避免它)。

路由器組件,而不是太大的不同從其他路由器的例子:

define('Router', ['backbone', ... ], 
     function (Backbone, ...) { 

      var MyRouter = Backbone.Router.extend({ 
       routes: { 
        'viewA': 'viewA', 
        'viewB': 'viewB' 
       }, 

       initialize: function() { 
        ... 
       }; 
      }, 
      viewA: function() { 
       ... 
      }, 

      viewB: function() { 
       ... 
      } 
}); 

return MyRouter; 
}); 

應用,創建路由器實例並觸發傳遞這種情況下,第一個視圖:

define('App', ['backbone', ... 
], function (Backbone, ...) { 

    function initialize() { 

     //route creation 
     if (!this.routes) 
      routes = new Router(this); 
     //backbone history start 
     Backbone.history.start(); 

     //ViewA navigation, bigbang 
     if (!this.viewA) 
      this.viewA = new ViewA({router: this.routes}); 
     this.viewA.render(); 
    } 

    return { 
     initialize: initialize 
    }; 
}); 

基本視角,基部構造定義所有視圖和導航方法:

define('BaseView', ['jquery', 'underscore', 'backbone', ... 
], function ($, _, Backbone, ...) { 
    var BaseView; 

    BaseView = Backbone.View.extend({ 
     id: '...', 

     constructor: function (options) { 
      this.router = options.router; 
      this.model = options.model; 
      Backbone.View.prototype.constructor.call(this); 
     }, 
     initialize: function() { 
      this.template = _.template(tpl); 
     }, 

     events: { 

     }, 
     render: function() { 
      $(this.el).html(this.template()); 

      return this; 
     }, 
     //Provides transparent navigation between views throught the backbonejs 
     //route mechanism 
     navigate: function(pageId) 
     { 
      this.router.navigate(pageId, {trigger: true}); 
     } 
    }); 

    return BaseView; 
}); 

查看實例,每個視圖從基地之一,而不是主幹延伸,繼承了基礎的行爲:

define('ViewA', ['jquery', 'underscore', 'backbone', 'BaseView' 
], function ($, _, Backbone, BaseView) { 
    var ViewA; 

    ViewA = BaseView.extend({ 
     id: '...', 

     constructor: function (options) { 
      this._super("constructor"); 
     }, 

     ... 
     foo: function() 
     { 
      ... 

      this.navigate("viewB"); 
     } 
    }); 

    return ViewA; 
}); 

這對我的作品,也可以在其他項目中重複使用。

1

對我來說,我向主應用程序中添加了一個對象,像這樣;你可以說windows.app.router.navigate({'',trigger:true})。在你看來,你可以說windows.app.router.navigate({'',trigger:true})。不知道在這種情況下全球範圍確定是否是好的做法,但它對我有用。

0

我有一個用於路由AMD模塊的新解決方案。

RequireJS路由器https://github.com/erikringsmuth/requirejs-router

這需要延遲加載AMD模塊的方式爲您導航到每一頁。使用Backbone路由器,您需要預先將所有視圖作爲依賴項。這會在首頁加載時加載所有應用程序的Javascript。當您導航到每個路由時,RequireJS路由器會延遲加載模塊。

示例main。js用於運行你的應用程序

define([], function() { 
    'use strict'; 

    // Configure require.js paths and shims 
    require.config({ 
    paths: { 
     'text': 'bower_components/requirejs-text/text', 
     'router': 'bower_components/requirejs-router/router' 
    } 
    }); 

    // Load the router and your layout 
    require(['router', 'js/layout/layoutView'], function(router, LayoutView) { 
    var layoutView = new LayoutView(); 
    // The layout's render method should draw the header, footer, and an empty main-content section 
    // then load the content section. 
    // render: function() { 
    // this.$el.html(this.template({model: this.model})); 
    // router.loadCurrentRoute(); 
    // } 

    // Configure the router 
    router 
     .registerRoutes({ 
     home: {path: '/', moduleId: 'home/homeView'}, 
     order: {path: '/order', moduleId: 'order/orderView'}, 
     notFound: {path: '*', moduleId: 'notFound/notFoundView'} 
     }) 
     .on('statechange', function() { 
     // Render the layout before loading the current route's module 
     layoutView.render.call(layoutView); 
     }) 
     .on('routeload', function(module, routeArguments) { 
     // Attach the content view to the layoutView's main-content section 
     layoutView.$('#main-content').replaceWith(new module(routeArguments).render().el); 
     }) 
     .init({ 
     // We're manually calling loadCurrentRoute() from layoutView.render() 
     loadCurrentRouteOnStateChange: false 
     }); 
); 
); 
define([], function() { 
    'use strict'; 

    // Configure require.js paths and shims 
    require.config({ 
    paths: { 
     'text': 'bower_components/requirejs-text/text', 
     'router': 'bower_components/requirejs-router/router' 
    } 
    }); 

    // Load the router and your layout 
    require(['router', 'js/layout/layoutView'], function(router, LayoutView) { 
    var layoutView = new LayoutView(); 
    // The layout's render method should draw the header, footer, and an empty main-content section 
    // then load the content section. 
    // render: function() { 
    // this.$el.html(this.template({model: this.model})); 
    // router.loadCurrentRoute(); 
    // } 

    // Configure the router 
    router 
     .registerRoutes({ 
     home: {path: '/', moduleId: 'home/homeView'}, 
     order: {path: '/order', moduleId: 'order/orderView'}, 
     notFound: {path: '*', moduleId: 'notFound/notFoundView'} 
     }) 
     .on('statechange', function() { 
     // Render the layout before loading the current route's module 
     layoutView.render.call(layoutView); 
     }) 
     .on('routeload', function(module, routeArguments) { 
     // Attach the content view to the layoutView's main-content section 
     layoutView.$('#main-content').replaceWith(new module(routeArguments).render().el); 
     }) 
     .init({ 
     // We're manually calling loadCurrentRoute() from layoutView.render() 
     loadCurrentRouteOnStateChange: false 
     }); 
); 
); 
相關問題