如何在没有父子关系的两个组件之间进行通信?

Kal*_*sev 5 angular-material angular

app.component.ts是我的 Angular 2 应用程序的入口点。它包含两个组件: header 和sidenav

@Component({
  selector: 'app-root',
  template: `
    <app-header></app-header>

    <app-sidenav></app-sidenav>
  `
})
export class AppComponent { }
Run Code Online (Sandbox Code Playgroud)

这是我想要实现的:在<app-header>组件内部我有一个(菜单)按钮,它应该触发<app-sidenav>组件的打开。

换句话说,按钮上的点击事件<app-header>应该触发组件open()内部的方法<app-sidenav>

  • header.component.ts

    @Component({
      selector: 'app-header',
      template: `
        <button (click)="onSidenavOpen()">Menu</button>
      `
    })
    export class HeaderComponent {
      constructor() { }
    
      onSidenavOpen() {
        // trigger the opening of the <app-sidenav> component
      }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • sidebar.component.ts

    @Component({
      selector: 'app-sidenav',
      template: `
        <md-sidenav #sidenav>
          // bla bla, sidebar
        </md-sidenav>
      `
    })
    export class SidenavComponent {
      constructor() { }
    
      open(sidenav) {
        sidenav.open();
      }
      close(sidenav) {
        sidenav.close();
      }
    }
    
    Run Code Online (Sandbox Code Playgroud)

我阅读了Angular 2 文档中的组件交互部分,但我正在努力寻找在这两个组件之间进行通信的最佳方法。我的总体意图是为每个组件封装尽可能多的逻辑。

你会如何处理我的用例?你会创建一个中间服务吗?请分享一个例子。

Sea*_*aal 6

您可以使用服务来允许两个单独的组件相互通信。在下面的示例中,使用的方法HeaderComponent将值推送到公开的。在初始加载时订阅此内容,并将响应推送的新值。ObservabletoggleSideNavSidebarServiceSidenavComponentObservable

侧边栏服务:

import { Injectable } from "@angular/core"

import { Observable, Subject } from "rxjs/Rx";

@Injectable()
export class SidebarService {

    private sidenavOpenSubject : Subject<boolean>;

    constructor() {
        this.sidenavOpenSubject = new Subject<boolean>();
    }

    toggleSideNav(opening: boolean): void {
        this.sidenavOpenSubject.next(opening);
    }

    onSideNavToggle(): Observable<boolean> {
        return this.sidenavOpenSubject;
    }

}
Run Code Online (Sandbox Code Playgroud)

标头组件:

@Component({
  selector: 'app-header',
  template: `
    <button (click)="onSidenavOpen()">Menu</button>
  `
})
export class HeaderComponent {
  constructor(private sidebarService: SidebarService) { }

  onSidenavOpen() {
    this.sidebarService.toggleSideNav(true);
  }
}
Run Code Online (Sandbox Code Playgroud)

侧边栏组件:

@Component({
  selector: 'app-sidenav',
  template: `
    <md-sidenav #sidenav>
      // bla bla, sidebar
    </md-sidenav>
  `
})
export class SidenavComponent implements OnInit {
    constructor(private sidebarService: SidebarService) { }

    ngOnInit(): void {
        this.sidebarService.onSideNavToggle().subscribe(
            (opening) => {
                if (opening) {
                    //Logic to open the sidenav here
                } else {
                    //Logic to close the sidenav here
                }
            }
        );
    }

    open(sidenav) {
        sidenav.open();
    }

    close(sidenav) {
        sidenav.close();
    }
}
Run Code Online (Sandbox Code Playgroud)

需要SidebarService在合适的模块中注册(例如您的AppModule)。

  • 注意:在`SidebarService`中导入大写“R”的“rxjs/Rx”。否则,它会导致我在节点 7.6 上运行 angular-cli 1.0.0-beta.31 时出错 (2认同)