【问题标题】:How to define and render submenu-items, using Aurelia's Router如何使用 Aurelia 的路由器定义和渲染子菜单项
【发布时间】:2016-05-13 18:42:40
【问题描述】:

在 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. 如何有条件地将每条路线呈现为常规(可点击)路线或带有子菜单的不可点击项?

我查看了RouteConfig docs,但似乎找不到关于“嵌套”子路由的任何信息。 Aurelia Getting Started 确实提供了有关子路线的信息,但在我看来,所有示例都与在另一个组件上显示“其他”或第二个菜单有关。

我确信这很简单,但我似乎无法解决它。

【问题讨论】:

  • 您是否在子导航中使用子路由器?问题在于,在您导航到子模块之前,路由不会注册,因此无法在主导航菜单中进行迭代......我已经设法使用包含的路由配置服务来实现类似的工作每个模块将查询以获取其路由的完整路由设置

标签: javascript aurelia


【解决方案1】:

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

Routes - 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 并传入主路由器的配置,否则这将不起作用。我发现这注册了主路由器上的所有路由,虽然这对我来说似乎真的很糟糕。

【讨论】:

    【解决方案2】:

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

    这在 Aurelia 中启用了一些非常强大的场景,但也带来了挑战,即在您导航到子路线之前,您的路线配置可能不存在。

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

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

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

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

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

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

    上述方法的缺点是您不能真正使用路由器轻松生成路由href(因为它使用父级来确定相对href是什么),最终您必须自己构建导航模型。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-31
    • 1970-01-01
    相关资源
    最近更新 更多