2017-03-12 3 views
0

Ich habe eine Navigationskomponente in meiner App, die mehrere Links zu verschiedenen Seiten hat, auf die über Routing zugegriffen wird. Ich möchte ein Navigationselement als "aktiv" anzeigen, wenn sich der Router derzeit auf derselben Seite befindet, auf die der Link verweist. Ich habe versucht, verschiedene Dinge, bis ich mit dem folgenden Code am Ende der dynamisch die CSS-Klasse setzt auf der aktuellen Route abhängig:Wie wird ein bedingtes Klassenattribut abhängig vom aktuellen Routing angewendet?

Vorlage:

<template> 
    <div> 
    <ul> 
     <li class.bind="overviewClass"><a href="#/batch/overview">Overview</a></li> 
     <li class.bind="completedJobsClass"><a href="#/batch/completed-jobs">Completed Jobs</a></li> 
     <li class.bind="jobDefinitionsClass"><a href="#/batch/job-definitions">Job Definitions</a></li> 
    </ul> 
    </div> 
</template> 

Ansichtsmodell:

import {inject} from 'aurelia-framework'; 
import {Router} from 'aurelia-router'; 

@inject(Router) 
export class Navigation { 
    constructor(private router: Router){ 
    } 

    get overviewClass(){ 
    return this.isActive("overview") ? "active" : ""; 
    } 

    get completedJobsClass(){ 
    return this.isActive("completed-jobs") ? "active" : ""; 
    } 

    get jobDefinitionsClass(){ 
    return this.isActive("job-definitions") ? "active" : ""; 
    } 

    isActive(routeName: string){ 
    if(this.router.currentInstruction != null && this.router.currentInstruction.config.name == routeName){ 
     return true; 
    } 

    return false; 
    } 
} 

Dieser Code in der Tat funktioniert wie erwartet. Mein Problem ist, dass ich eine dynamischere Lösung finden muss, weil diese Lösung nicht skaliert. Zur Zeit muss ich einen Getter für jedes Navigationselement hinzufügen, das ich implementieren muss.

Ich habe versucht, eine Funktion anstelle eines Getters zu verwenden, aber das Problem war in allen meinen Fällen, dass der Wert this.router.currentInstruction null war.

Gibt es eine effiziente Möglichkeit, eine Funktion mit einem Parameter zu implementieren, so dass ich sie aus der Vorlage binden kann, ohne für jede Verknüpfung eine Funktion oder einen Getter hinzufügen zu müssen?

Vielen Dank für Ihre Hilfe.

Antwort

2

Sie können die integrierte Möglichkeit nutzen, wenn das überprüfen Route, auf der du bist, ist die aktive. Aurelia Router gibt Ihnen diese Eigenschaft bereits. Wenn es eine Route gibt, die nicht zur Benutzeroberfläche hinzugefügt werden soll, können Sie das Attribut nav für Ihre Routendefinition verwenden und es auf false setzen. Es wird nicht zum Array route.navigation hinzugefügt.

Wie bei diesem Beispiel:

Router-Konfiguration

{ route: 'users',   name: 'users',  moduleId: 'users/index', nav: true }, 
    { route: 'users/:id/detail', name: 'userDetail', moduleId: 'users/detail' }, 

, wo Sie Ihr Menü

<li repeat.for="row of router.navigation" class="${row.isActive ? 'active' : ''}"> 
+0

Genau das habe ich gesucht. Erwähnenswert ist, dass Sie mit der Eigenschaft "href" auf die URL zugreifen können und der Anzeigename mit der Eigenschaft "title" angegeben werden kann. Die Eigenschaft "href" muss nicht manuell festgelegt werden. Sie ruft ihren Wert aus der Eigenschaft "route" ab, falls angegeben. Meine endgültige Lösung sieht so aus: '

  • ${row.title}
  • ' –

    0

    verwendete ich ein benutzerdefiniertes Attribut:

    // is-active.js

    import { Router } from 'aurelia-router'; 
    import { EventAggregator } from 'aurelia-event-aggregator'; 
    import { inject, customAttribute, DOM, bindable } from 'aurelia-framework'; 
    
    const EVENT_NAME = 'router:navigation:success'; 
    
    @inject(DOM.Element, Router, EventAggregator) 
    @customAttribute('is-active') 
    @bindable({ name: 'route' }) 
    @bindable({ name: 'selector', defaultValue: 'is-active' }) 
    export class IsActiveCustomAttribute { 
    
        constructor(element, router, eventAggregator) { 
         this.router = router; 
         this.element = element; 
         this.ea = eventAggregator; 
        } 
    
        attached() { 
         this.subscriber = this.ea.subscribe(EVENT_NAME, this.handler.bind(this)); 
        } 
    
        detached() { 
         this.subscriber.dispose(); 
        } 
    
        handler() { 
         let config = this.router.currentInstruction.config; 
         let currentRoute = config.name; 
         let hasSelector = this.element.classList.contains(this.selector); 
         let matchChildren = config.route.split('/', 1)[0] === this.route; 
    
         if (this.route === currentRoute || matchChildren) { 
          if (!hasSelector) { 
           this.element.classList.add(this.selector); 
          } 
         } else if (hasSelector) { 
          this.element.classList.remove(this.selector); 
         } 
        } 
    } 
    

    // html

    <nav class="mdl-navigation mdl-layout--large-screen-only"> 
        <a class="mdl-navigation__link" 
         is-active="route: courses" 
         route-href="route: courses">Courses</a> 
    
        <a class="mdl-navigation__link" 
         is-active="route: freebies" 
         route-href="route: freebies">Freebies</a> 
    
        <a class="mdl-navigation__link" 
         is-active="route: blog" 
         route-href="route: blog">Blog</a> 
    </nav> 
    
    +0

    Vielen Dank für Ihre Antwort angezeigt werden sollen. Ich bin sicher, dass das funktioniert und Sie es in der Produktion verwenden, denke ich. Aber für mich ist die Antwort von @maximedubois, wonach ich gesucht habe. Diese Lösung scheint der Weg zu sein, das Framework für die "harte Arbeit" zu nutzen. –

    Verwandte Themen