【问题标题】:Angular router link active nested menu角路由器链接活动嵌套菜单
【发布时间】:2019-04-17 09:42:43
【问题描述】:

我正在尝试制作带有角度路线的嵌套菜单。

如果嵌套路由处于活动状态,我需要将类应用于嵌套路由,如果其子组件处于活动状态,则将类应用于父组件。

我如何实现这一目标?现在我正在做递归菜单构建,以便在需要多级嵌套时使用。

component.html

<a (click)="toggleActive()" [class.active]="isActive" [routerLink]="menuItem.link" *ngIf="menuItem.link; else noLink">
  <i *ngIf="menuItem.faClass" class="fa fa-{{menuItem.faClass}}"></i>
  {{menuItem.name}} <span *ngIf="menuItem.children && menuItem.children.length > 0" class="fa fa-chevron-down"></span>
</a>

<ng-container *ngIf="menuItem.children && menuItem.children.length > 0">
  <ul class="nav child_menu" [class.active]="isActive" routerLinkActive="active"
      *ngFor="let item of menuItem.children">
    <li menu-item [menuItem]="item" (checkActive)="updateActiveState()"></li>
  </ul>
</ng-container>

<ng-template #noLink>
  <a (click)="toggleActive()" [class.active]="isActive">
    <i *ngIf="menuItem.faClass" class="fa fa-{{menuItem.faClass}}"></i>
    {{menuItem.name}} <span *ngIf="menuItem.children && menuItem.children.length > 0" class="fa fa-chevron-down"></span>
  </a>
</ng-template>

组件.ts

@Component({
  selector: '[menu-item]',
  templateUrl: './menu-item.component.html',
  styleUrls: ['./menu-item.component.scss'],
  host: {
    '[class.active]': 'hostActive && isActive',
    '[class.active-sm]': 'hostActiveSm && isActive'
  }
})
export class MenuItemComponent implements OnInit, AfterViewInit, OnChanges {

  public menuSize;
  public isActive = false;

  @Input() menuItem: MenuItem;
  @Output() checkActive: EventEmitter<void> = new EventEmitter<void>();
  @ViewChild(MenuItemComponent) menuComponent: MenuItemComponent;

  private hostActive = true;
  private hostActiveSm = false;

  @HostBinding('class') hostClass = this.hostActive && this.isActive ? 'active' : this.hostActiveSm && this.isActive ? 'active-sm' : '';

  constructor(
    private router: Router,
    private uss: UiStateService,
  ) {
  }

  ngOnInit() {
    this.uss.menuSubject.subscribe(msg => {
      this.menuSize = msg;
      if (this.menuSize === MenuSizes.sm) {
        this.hostActive = false;
        this.hostActiveSm = true;
      } else {
        this.hostActive = true;
        this.hostActiveSm = false;
      }
      this.updateActiveState();
    });

    this.router.events.subscribe((e: Event) => {
      if (e instanceof NavigationEnd) {
        this.updateActiveState();
      }
    });
  }

  ngOnChanges() {
  }

  ngAfterViewInit() {
    this.updateActiveState();
  }

  public toggleActive(): void {
    this.isActive = !this.isActive;
    // if (this.menuComponent) {
    //   this.menuComponent.isActive = true;
    // }
  }

  private updateActiveState(): void {
    // reset previous state
    this.isActive = false;
    if (this.menuComponent) {
      this.menuComponent.isActive = false;
    }

    // Check state of item with no els
    const url = this.router.url;
    console.log('URL', url, 'Menu link', this.menuItem.link);
    console.log(url.match('/' + this.menuItem.link + '$/'));
    if (this.menuItem && this.menuItem.link && url.match('/' + this.menuItem.link + '$/')) {
      this.isActive = true;
      this.checkActive.emit();
    }

    if (this.menuComponent) {
      console.log('Menu component');
      console.log(this.menuComponent, this.menuComponent.menuItem.link);
      this.isActive = true;
    }
  }

}

有没有办法从组件中知道其路由是否处于活动状态?诀窍是我使用的是[routerLink] 而不是routerLink,这样我就可以将. 作为指向根页面的链接传递。

更新

我能重现的最好的stackblitz 尝试访问“仪表板”。它应该向父 li 添加一个“活动”类。如果您自己添加它,您会在它的元素上看到应用的类,并在右侧看到一个彩色条。

【问题讨论】:

  • 你能创建 stackblitz 示例吗?
  • 这太复杂了,因为它需要几乎完整的应用程序才能重新创建
  • @yurzui 更新了问题

标签: angular routing


【解决方案1】:

也许你可以尝试在任何组件中访问 ActivatedRoute

import { Router, ActivatedRoute} from '@angular/router';    

 constructor(private router: Router, private activatedRoute:ActivatedRoute) {
    console.log(activatedRoute.snapshot.url)  // array of states
    console.log(activatedRoute.snapshot.url[0].path) 
 }

希望这会有所帮助!

【讨论】:

  • 请重新阅读我的问题的结尾。我可能会通过.,因为我正在使用 [routerLink],我不想手动匹配这种情况,因为它可能会随着时间而改变。
  • 对不起,我弄错了,但你说得很清楚'有没有办法从组件中知道它的路由是否处于活动状态?'。我回答那个。祝你好运
【解决方案2】:

StackBlitz

所有这些功能都内置在 Angular 的路由器模块中。这是子路线背后的全部想法。如果一个路由真的是一个父组件,它应该是路由中的一个父组件。通过这样做,您可以简单地检查父路由是否处于活动状态,而不是在应用程序组件中任意分配的任何路由。

此外,这具有允许仪表板简单地路由到 ['../sibling'] 的巨大好处

在我的子路由特别是 /home/home.routes 中,您将看到一个注释行,如果这是所需的行为,它将使仪表板自动加载。

您已经在动态菜单项中使用routerLinkActive,但要采用最直接的方法,它应该在绑定到 routerLink 的项目上,如here 所述。

您可能会遇到的最大问题是嵌套的 routerLink 元素在 DOM 中不能很好地发挥作用,正如 this question 中所讨论的那样,因此您需要停止传播。

app-component.html

<ul app-menu-item 
  class="nav side-menu"
  [menu]="menu">
</ul>

菜单项.html:

<li
  *ngFor="let item of menu"
  [routerLink]="item.link"
  routerLinkActive="active"
  (click)="stop($event)">

    {{item.name}}

    <ul app-menu-item
      *ngIf="item.children"
      class="nav side-menu"
      [menu]="item.children">
    </ul>
</li>

我会补充一点,虽然它没有回答你问题中的标题,但这个问题最容易通过使用父路由解决,然后按如下方式设置 menu-item.html:

<li *ngFor="let item of menu">
  <a [routerLink]="item.link" routerLinkActive="active">
    {{item.name}}
  </a>
  <ul class="nav side-menu"
  *ngIf="item.children"
  app-menu-item [menu]="item.children">
  </ul>
</li>

然后在你的 scss 中使用同级选择器来显示或隐藏菜单。

【讨论】:

  • 这个想法是包含仪表板的“主页”应该有活动的类。在实际应用中,它有点像手风琴,当它的后代处于活动状态时,我需要扩展一个项目。 (通过将类应用于项目)。
  • 在我的示例中,样式已关闭,但它确实具有活动类。看看here。可能会更清楚。
  • 你做错了。我已经告诉过递归,同时在您的示例中它不存在。这意味着您只有 2 级菜单,如果我通过 dashboard 孩子,它不会呈现它们。
  • 根据您的反馈更新了答案和 stackblitz。
  • 干得不错,但还是不一样 :) 您的实现现在缺少无链接项之类的东西,因为当父项具有链接时这是一件奇怪的事情,同时它只是一个分组项。因为,我们不能做一个有条件的路由链接(只有当值存在时才存在 [routerLink]="" 指的是主页)我们在将这个 routerActive 状态传播给本身没有链接的父级时确实存在问题.
【解决方案3】:

我已经设法解决它。 StackBlitz

主要是通过在navigateEnd事件中使用没有时间的setTimeOut来实现的,这样我就可以检查isActive的状态并获取值(如果没有setTimeout,则该值是“从过去”获取的意思拍摄时未更新)。它的工作方式有点棘手,但确实有效

【讨论】:

    【解决方案4】:

    通过将模板变量分配给子级并像这样在父级上检查它来实现更简单 -

    <li [ngClass]="{ 'is-expanded': rla.isActive }">
      <!-- is-expanded or active or whatever class in your template makes it active. -->
      <a>Parent Item</a>
      <ul class="treeview-menu">
        <li>
          <a routerLink="/child" routerLinkActive="active" #rla="routerLinkActive"
            >Child</a
          >
        </li>
      </ul>
    </li>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-05-11
      • 1970-01-01
      • 1970-01-01
      • 2021-05-23
      • 2023-02-05
      • 1970-01-01
      • 2018-04-09
      • 1970-01-01
      相关资源
      最近更新 更多