由孩子操纵父DOM吗?

时间:2017-08-09 20:35:53

标签: angular angular-ui-router

我的设置如下:

<nav>
    <li>
        <a someClassToggleDirective>Menu 1</a> <!-- This anchor element toggle determines if ul.sub-menu should be expanded (displayed) -->
        <ul class="sub-menu">   <!-- This is displayed when it's first sibling 'a' has 'open' class -->
            <li routerLinkActive="active"><a routerLink="childComp1">Child Component 1</a></li>
            <li routerLinkActive="active"><a routerLink="childComp2">Child Component 2</a></li>
            ...
        </ul>
    </li>
    <li>
        <a someClassToggleDirective>...</a>
        <ul class="sub-menu">
            ...
        </ul>
    </li>
    ...
</nav>
<router-outlet></router-outlet>

要加载任何组件,请单击li项,然后展开它的子菜单ul。单击其中一个子菜单项会在<router-outlet></outlet>中加载相应的组件,并将子菜单项设置为活动。然后路线将是[root]/childComp1。但是,如果我使用浏览器的地址栏直接导航到[root]/childComp1,则会加载该组件,但不会展开活动子组件的父ul

那么,我该如何扩展呢?要展开子菜单(ul),我需要在其兄弟open中添加一个类a。我该怎么做呢?我想到的一种方法是使用this.router.url来确定组件,并根据路径名称展开相应的sub-menu。但我觉得这不是最好的方法。有没有更好的方法?我想避免使用像jQuery这样的第三方库。

1 个答案:

答案 0 :(得分:1)

您可以使用@ContentChildren装饰器在子菜单中获取RouterLinkActive的所有实例。并检测是否存在活动链接。

例如,您可以创建指令,该指令保留链接列表。并在每个路线上更改切换expand prop。

<强>指令

import {Directive, HostListener, HostBinding, ContentChildren, QueryList} from '@angular/core';
import {Router, RouterLinkActive, NavigationEnd} from '@angular/router';
import 'rxjs/Rx';
import { Subscription } from 'rxjs/Subscription';

@Directive({ selector: '[listToggle]' })
export class ListToggleDirective {

  // Collect RouterLinkActive instances
  @ContentChildren(RouterLinkActive) links: QueryList<RouterLinkActive>;

  // If expand=true - show submenu
  @HostBinding('class.expand')
  expand: boolean;

  routerSub: Subscription;

  constructor(private router: Router) {

  }


  ngAfterContentInit(): void {
    // Detect if there is active links
    this.routerSub = this.router.events
      .filter(e => e instanceof NavigationEnd)
      .subscribe(() => this.detectActiveLink());
  }

  ngOnDestroy(): void {
    if (this.routerSub) {
      this.routerSub.unsubscribe();
    }
  }

  detectActiveLink(): void {
    setTimeout(() => {
      const hasActive = this.links.some(link => link.isActive);
      this.expand = hasActive;
    });
  }

}

<强>用法

<ul>
    <li listToggle>
        <a>Open menu 1</a>
        <ul class="sub-menu">
            <a routerLink="/cmp1" routerLinkActive="active">cmp1</a>
            <a routerLink="/cmp2" routerLinkActive="active">cmp2</a>
        </ul>
    </li>
    <li listToggle>
        <a>Open menu 2</a>
        <ul class="sub-menu">
            <a routerLink="/cmp3" routerLinkActive="active">cmp3</a>
        </ul>
    </li>
</ul>

<强>样式

li[listtoggle] {
    &.expand .sub-menu {
        display: block;
    }
    .sub-menu {
        display: none;
    }
}

希望这有帮助