简体   繁体   English

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

[英]How to define and render submenu-items, using Aurelia's Router

In an Aurelia app, I've defined a simple route like this: 在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;
}

This works perfectly as all the examples mention, by implementing repeat.for and href.bind like this: 通过像这样实现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>

The challenge in my scenario is that I want to dynamically render routes with submenu-items to this menu as well. 我的场景中的挑战是我想要将带有子菜单项的路线动态渲染到此菜单。 Something like this: 像这样的东西:

<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>

What puzzles me are two things: 令我困惑的是两件事:

  1. How do I properly define the submenu-items in the route config? 如何正确定义路径配置中的子菜单项?
  2. How can I conditionally render each route as either a regular (clickable) route, or as a non-clickable item with submenu's? 如何有条件地将每条路线渲染为常规(可点击)路线,或者作为具有子菜单的不可点击项目?

I've looked in the RouteConfig docs but can't seem to find any info on 'nested' subroutes. 我查看了RouteConfig文档,但似乎无法找到有关'嵌套'子路径的任何信息。 The Aurelia Getting Started does provide info about child routes, but all the samples seem to me to be related to displaying "other", or second menu's on another component. Aurelia入门确实提供了有关子路线的信息,但在我看来,所有样本都与在另一个组件上显示“其他”或第二个菜单有关。

I'm sure it's quite trivial, but I just can't seem to get a fix on it. 我确定这很简单,但我似乎无法解决它。

I solved this problem with a ValueConverter. 我用ValueConverter解决了这个问题。 This is only for two levels, but with a little change it could support more. 这仅适用于两个级别,但只需稍加改动即可支持更多级别。

Routes - settings.parentMenu defines under which menu it will appear. 路由 - 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 - Groups the submenus under the parent 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 - pipe the router.navigation into the subMenu value converter and then check for children when binding the submenu. 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>

Whether this is the correct way to do it I don't know, but it's the least "hacky" way I found. 这是否是正确的方法,我不知道,但这是我找到的最不“hacky”的方式。 If you are using child routes then this won't work unless you inject the child routers into your app.js (or wherever you define your routes) and calling configureRouter and passing in the main router's config. 如果您正在使用子路由,那么除非您将子路由器注入app.js(或者您定义路由的任何位置)并调用configureRouter并传入主路由器的配置,否则这将无效。 I found that this registered all the routes on the main router, although it seems really bad to me. 我发现这记录了主路由器上的所有路由,虽然它对我来说似乎非常糟糕。

The problem you have is that sub routes tend to use child routers. 您遇到的问题是子路由倾向于使用子路由器。

This enables some pretty powerful scenarios in Aurelia but presents the challenge that your route configuration might not be present until you have navigated to a child route. 这样可以在Aurelia中实现一些非常强大的场景,但是在您导航到子路径之前,可能会出现路径配置可能不存在的挑战。

I've handled this scenario before by proving a routing service that surfaces a routing tree as a single object with some helper methods to transform parts of this into a route config object which Aurelia can consume. 我之前通过证明路由服务将路由树表示为单个对象并使用一些辅助方法将其部分转换为Aurelia可以使用的路由配置对象来处理这种情况。

This is then injected into the sub modules and they query it to configure the router 然后将其注入子模块,并查询它以配置路由器

The nav menu component can then look at this tree to build the menu structure ahead of any child modules being loaded. 然后,导航菜单组件可以查看此树,以便在加载任何子模块之前构建菜单结构。

Mike Graham also does a similar thing but he just sets all the route config up front (using a "level" variable on the route config to determine the menu heirarchy): Mike Graham也做了类似的事情,但他只是预先设置了所有的路由配置(在路由配置上使用“level”变量来确定菜单层次结构):

Aurelia: child router routes display in "main" nav-bar and child view in app.html <router-view> element? Aurelia:子路由器路由显示在app.html <router-view>元素的“main”导航栏和子视图中?

The disadvantage to that approach is that you need to know about submodules ahead of time in order to configure the router. 这种方法的缺点是您需要提前了解子模块以配置路由器。 (part of the power of child routers is that they can just register at runtime and can be "dropped in" without any config anywhere else in the hosting app - this negates that advantage) (子路由器的一部分功能是它们只能在运行时注册,并且可以“放入”而无需托管应用程序中的任何其他任何配置 - 这否定了这一优势)

The disadvantage of the aforementioned approach is that you can't really generate route hrefs using the router easily (since it uses the parent to figure out what the relative href is) and you end up having to build the navmodel yourself. 前面提到的方法的缺点是你不能轻易地使用路由器生成路由href(因为它使用父亲来计算相对href是什么),你最终必须自己构建navmodel。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM