2013-10-20 57 views
8

我已經構建了一個應用程序,並且想要顯示一個兩層菜單,並且這兩個層始終可用。 Durandal 2.0 introduced their new router,支持「子路由器」,可以更輕鬆地進行深度鏈接。Durandal 2.0 - 用於嵌套菜單的子路由器?

我的問題 - 我可以有我的「孩子」的航行路線永久裝載(當父母不活躍的子菜單呈現的),或者是「子路由器的設計旨在懶加載它們來評估他們曾經深度鏈接被評估?

的迪朗達爾示例顯示主導航註冊一個圖示的路線,然後當視圖模型被加載/激活,子路由器被登記。

例如:在具備迪朗達爾2.0的例子中,勉內華達州被登記在shell.js

router.map([ 
       { route: ['', 'home'], moduleId: 'hello/index', title: 'Validation test', nav: true }, 
       { route: 'knockout-samples*details', moduleId: 'ko/index',    title: 'Knockout Samples', nav: true, hash: '#knockout-samples' } 
      ]).buildNavigationModel() 
       .activate(); 

然後是ko/index.js視圖模型註冊兒童(上activate()

var childRouter = router.createChildRouter() 
     .makeRelative({ 
      moduleId:'ko', 
      fromParent:true 
     }).map([ 
      { route: '',    moduleId: 'helloWorld/index',  title: 'Hello World',   type: 'intro' }, 
      { route: 'helloWorld',  moduleId: 'helloWorld/index',  title: 'Hello World',   type: 'intro',  nav: true}, 
      { route: 'clickCounter', moduleId: 'clickCounter/index',  title: 'Click Counter',   type: 'intro',  nav: true} 
     ]).buildNavigationModel(); 

鑑於我期待在一個地方定義我的路線,例如:

var routes = [ 
    { route: ['', 'home'], 
     moduleId: 'hello/index', 
     title: 'Validation test', 
     nav: true }, 
    { route: 'knockout-samples*details',  
     moduleId: 'ko/index', 
     moduleRootId: 'ko', // Custom property to make child routes easier    
     title: 'Knockout Samples', 
     nav: true, 
     hash: '#knockout-samples', 
     childRoutes: [ 
      { route: '',    moduleId: 'helloWorld/index',  title: 'Hello World',   type: 'intro' }, 
      { route: 'helloWorld',  moduleId: 'helloWorld/index',  title: 'Hello World',   type: 'intro',  nav: true}, 
      { route: 'clickCounter', moduleId: 'clickCounter/index',  title: 'Click Counter',   type: 'intro',  nav: true} 
     ]} 
    ]) 

而我正在努力的部分是註冊孩子的路線,並讓他們在瀏覽時正確地蒸發。 (渲染菜單稍後會出現...)

// Load routes    router.map(routes.navRoutes).buildNavigationModel().mapUnknownRoutes(function(instruction) 
{ 
    logger.logError('No Route Found', instruction.fragment, 'main', true); 
}); 

// Try load child routes... 
$.each(routes.navRoutes, function(index, parentRoute) { 
    if (!parentRoute.childRoutes) { 
       return; 
      } 

      var childRouter = router.createChildRouter() 
       .makeRelative({ 
        moduleId: parentRoute.moduleRootId, 
        fromParent: true // also tried false + non-splat routes... 
       }).map(parentRoute.childRoutes).buildNavigationModel(); 
     }); 

我在獲取此導航欄時遇到了各種錯誤。當試圖計算哈希時(主要來自未激活的父項或子項),主要是內部的router.js錯誤 - 因此所有哈希都已定義。

一旦我得到它來映射導航,子路徑似乎無法訪問 - 他們只是無誤地加載主圖示頁面。

所以我想知道如果我正確地做這件事嗎? (預先註冊所有兒童路線,目標是呈現兩層菜單)。

我在考慮使用諸如Durandal 1.2 answer about subrouting之類的東西,使用平面路由註冊,自定義'isSameItem'函數&計算的observables來呈現2層導航。

回答

14

我希望我可以幫你一下。

您可以永久裝載「孩子」路由器嗎?

據我所知,你不能(或者說沒有簡單的方法來實現這一點)。子路由器旨在爲特定視圖提供子路由功能 - 您可以將它們視爲Durandal視圖中的Durandal導航。如果我們檢查Durandal頁面上的示例代碼,我們可以很容易地看到子路由生命期與給定視圖相關聯。更重要的是,如果我們檢查創建子路由的函數的代碼,我們將看到它創建新的路由器並且僅存儲對父路由器的引用 - 父路由器(在大多數情況下主路由器)沒有對其子的引用

router.createChildRouter = function() { 
      var childRouter = createRouter(); 
      childRouter.parent = router; 
      return childRouter; 
     }; 

在主路由器中實現多級路由可以做些什麼?

我以前有過類似的問題,但是使用舊版的Durandal。對於這個問題,我已經開始從零開始,你給了一點,並修改它 - 我擺脫了甩掉路線,因爲它打算用於兒童路線,我的解決方案將不會使用它們。

var routes = [ 
       { 
        route: ['', 'home'], 
        moduleId: 'viewmodels/home', 
        title: 'Validation test', 
        nav: true 
       }, 
       { 
        route: 'knockout-samples', 
        moduleId: 'viewmodels/ko/index', 
        moduleRootId: 'viewmodels/ko', // Custom property to make child routes easier    
        title: 'Knockout Samples', 
        nav: true, 
        hash: '#knockout-samples', 
        childRoutes: [ 
         { route: 'simpleList', moduleId: 'simpleList', title: 'SimpleList', nav: true, hash : 'simpleList' }, 
         { route: 'clickCounter', moduleId: 'clickCounter', title: 'Click Counter', nav: true, hash : 'clickCounter' } 
        ] 
       } 
      ]; 

下一步是將這個用戶友好的定義轉換爲路由表,它可以很容易地在主路由器中註冊。

$.each(routes, function(index, route) { 
       if (route.childRoutes === undefined) 
        return 
       $.each(route.childRoutes, function(index, childRoute) { 
        childRoute.route = route.route + '/' + childRoute.route; 
        childRoute.moduleId = route.moduleRootId + '/' + childRoute.moduleId; 
        childRoute.title = route.title + '/' + childRoute.title; 
        childRoute.hash = route.hash + '/' + childRoute.hash; 
        childRoute.parent = route.moduleRootId; 
       }); 
       routes = routes.concat(route.childRoutes); 
      }); 

最後一步是標準註冊路由器並激活它。

return router.map(routes) 
       .buildNavigationModel() 
       .activate(); 

如何渲染寄存器路由以保持多級佈局?

我的代碼與Bootstrap 2.3.0一起使用,並將多級菜單渲染爲下拉按鈕。當路由沒有子路由時(所以只是簡單的路由)並且沒有父路由(它的第一級導航)被呈現爲簡單按鈕。如果路線具有子路線,則其渲染爲下拉按鈕,子路線添加到下拉列表。

<div class="btn-group" data-bind="foreach: router.navigationModel"> 
      <!-- ko if: $data.childRoutes === undefined && $data.parent === undefined --> 
       <a data-bind="css: { active: isActive }, attr: { href: hash }, text: title" class="btn btn-info" href="#"/> 
      <!-- /ko --> 
      <!-- ko if: $data.childRoutes !== undefined --> 
      <div class="btn-group btn-info"> 
       <a data-bind="css: { active: isActive }, attr: { href: hash }, text: title" class="btn btn-info" href="#"/> 
       <button class="btn btn-info dropdown-toggle" data-toggle="dropdown"> 
        <span class="caret"/> 
       </button> 
       <ul class="dropdown-menu" data-bind="foreach: childRoutes"> 
        <a data-bind="css: { active: isActive }, attr: { href: hash }, text: title" class="btn btn-info" href="#"/> 
       </ul> 
      </div> 
      <!-- /ko --> 
     </div> 

樣式可能需要進行位打磨,但總體邏輯完成。

+0

我以前在路由器對象上使用了不同的方法來做到這一點,但我認爲這有點優雅,我非常喜歡這個解決方案。 – MattSizzle