如何使用Aurelia的路由器定义和渲染子菜单项

时间:2016-05-13 18:42:40

标签: javascript aurelia aurelia-router

在Aurelia应用程序中,我已经定义了这样一条简单的路线:

configureRouter(config: RouterConfiguration, router: Router) {
    config.title = 'Marino';
    config.map([
        { route: ['', 'home'], name: 'home', moduleId: './pages/home/home', nav: true, title: 'Home' },
        { route: 'colors', name: 'colors', moduleId: './pages/colors/overview', nav: true, title: 'Colors' }
    ]);

    this.router = router;
}

通过像这样实现repeat.for和href.bind,这在所有示例中都很有效:

<ul class="main-navigation">
    <li repeat.for="row of router.navigation" class="${row.isActive ? 'active' : ''}">
        <a class="btn btn-primary" href.bind="row.href">${row.title}</a> 
    </li>
</ul>

我的方案中的挑战是我想动态地将带有子菜单项的路线渲染到此菜单。像这样:

<ul class="main-navigation">

    <!-- the regular 'regular' menu and works just fine -->
    <li repeat.for="row of router.navigation" class="${row.isActive ? 'active' : ''}">
        <a class="btn btn-primary" href.bind="row.href">${row.title}</a> 
    </li>

    <!-- 
        below is the pickle; a different kind of element (non-clickable),
        but with child elements
    -->

    <li class="main-navigation-dropdown">
        <a class="btn btn-primary">Menu with Submenu-items</a> 
        <div class="horizontal-dropdown-menu">
            <a class="btn btn-primary sideline">Submenu 1</a> 
            <a class="btn btn-primary sideline">Submenu 2</a> 
            <a class="btn btn-primary sideline">Submenu 3</a> 
        </div>
    </li>                            
</ul>

令我困惑的是两件事:

  1. 如何正确定义路线配置中的子菜单项?
  2. 如何有条件地将每条路线呈现为常规(可点击)路线,或者作为带有子菜单的不可点击的项目?
  3. 我已查看RouteConfig docs但似乎无法找到有关嵌套&#39;的任何信息。子路径。 Aurelia Getting Started确实提供了有关子路线的信息,但在我看来,所有样本都与在另一个组件上显示&#34;其他&#34;或第二个菜单有关。

    我确定它非常简单,但我似乎无法解决问题。

2 个答案:

答案 0 :(得分:3)

我用ValueConverter解决了这个问题。这仅适用于两个级别,但只需稍加改动即可支持更多级别。

路线 - settings.parentMenu定义它将出现在哪个菜单下。

export class App {
  configureRouter(config, router) {
    config.title = 'Aurelia';
    config.map([
      { route: ['', 'welcome'],   name: 'welcome',          moduleId: 'welcome',    nav: true, title: 'Welcome',   settings: { icon : 'fa-th-large'} },
      { route: '#',               name: 'admin',            moduleId: 'admin',      nav: true, title: 'Admin',     settings: { icon : 'fa-user' } },
      { route: 'admin/templates', name: 'admin-templates',  moduleId: 'users/users',  nav: true, title: 'Templates', settings: { parentMenu: 'Admin'} }
    ]);
    this.router = router;
  }
}

subMenu.js - 将父级下的子菜单分组

export class SubMenuValueConverter {
    toView(routerMenuItems) {
        var menuItems = [];
        routerMenuItems.forEach(function (menutItem) {
            if (menutItem.settings.parentMenu) {
                // Submenu children
                var parent = menuItems.find(x => x.title == menutItem.settings.parentMenu);
                // If it doesn't exist, then something went wrong, so not checking 
                parent.children.push(menutItem);                   
            } else {
                 // Just insert.  It should not be there multiple times or it's a bad route
                menuItems[menutItem] = menuItems[menutItem] || [];
                // Create empty children
                menutItem.children = [];
                menuItems.push(menutItem);
            }
        });

        return menuItems;
    }
}

nav-bar.html - 将router.navigation传递到subMenu值转换器中,然后在绑定子菜单时检查子节点。

<template bindable="router">
  <require from="./subMenu"></require>
  <nav role="navigation">
    <li repeat.for="row of router.navigation | subMenu" class="${row.isActive ? 'active' : ''}">
        <a href="${row.children.length == 0 ? row.href : 'javascript:void(0);'}">
        <i class="fa ${row.settings.icon}"></i>
        <span class="nav-label">${row.title}</span>
        </a>

        <ul if.bind="row.children.length > 0" class="nav nav-second-level">
            <li repeat.for="sub of row.children" class="${sub.isActive ? 'active' : ''}">
                <a href.bind="sub.href">
                    <i class="fa ${subrow.settings.icon}"></i>
                    <span class="nav-label">${sub.title}</span>
                </a>
            </li>
        </ul>
    </li>
  </nav>
</template>

这是否是正确的方法,我不知道,但这是我找到的最不“hacky”的方式。如果您正在使用子路由,那么除非您将子路由器注入app.js(或者您定义路由的任何位置)并调用configureRouter并传入主路由器的配置,否则这将无效。我发现这记录了主路由器上的所有路由,虽然它对我来说似乎非常糟糕。

答案 1 :(得分:2)

您遇到的问题是子路由倾向于使用子路由器。

这可以在Aurelia中实现一些非常强大的场景,但是在您导航到子路径之前,可能会出现路线配置可能不存在的挑战。

我之前通过证明一个路由服务将路由树作为单个对象表示,并使用一些辅助方法将其部分转换为Aurelia可以使用的路由配置对象来处理这种情况。

然后将其注入子模块,并查询它以配置路由器

然后,导航菜单组件可以查看此树,以便在加载任何子模块之前构建菜单结构。

Mike Graham也做了类似的事情,但他只是预先设置了所有的路由配置(在路由配置上使用“level”变量来确定菜单层次结构):

Aurelia: child router routes display in "main" nav-bar and child view in app.html <router-view> element?

这种方法的缺点是您需要提前了解子模块以配置路由器。 (子路由器的一部分功能是它们可以在运行时注册,并且可以“放入”而无需在托管应用程序中的任何其他任何配置 - 这否定了这一优势)

上述方法的缺点是你不能轻易地使用路由器生成路由href(因为它使用父亲来计算相对href是什么),你最终必须自己构建navmodel。 / p>