【问题标题】:How to communicate between two components with no parent-child relationship?如何在没有父子关系的两个组件之间进行通信?
【发布时间】:2017-07-05 20:48:56
【问题描述】:

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

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

    <app-sidenav></app-sidenav>
  `
})
export class AppComponent { }

这是我想要实现的目标:在 &lt;app-header&gt; 组件内,我有一个(菜单)按钮,它应该会触发 &lt;app-sidenav&gt; 组件的打开。

换句话说,&lt;app-header&gt; 中按钮的点击事件应该触发&lt;app-sidenav&gt; 组件内的open() 方法。

  • 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
      }
    }
    
  • 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();
      }
    }
    

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

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

【问题讨论】:

标签: angular angular-material


【解决方案1】:

您可以使用服务来允许两个独立的组件相互通信。在下面的示例中,HeaderComponent 使用 SidebarServicetoggleSideNav 方法将值推送到暴露的 ObservableSidenavComponent 在其初始加载时订阅此 Observable 并将响应推送的新值。

侧边栏服务:

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

}

标头组件:

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

  onSidenavOpen() {
    this.sidebarService.toggleSideNav(true);
  }
}

侧边栏组件:

@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();
    }
}

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

【讨论】:

  • 注意:在SidebarService 中导入“rxjs/Rx”,大写“R”。否则,它会导致我在节点 7.6 上运行 angular-cli 1.0.0-beta.31 时出错
  • 在这种情况下,如何捕捉点击侧边栏外部并关闭侧边栏的瞬间?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-07
  • 2017-06-16
  • 2020-08-30
相关资源
最近更新 更多