0

我正在尝试为具有相互依赖组件之类的 Angular 2 应用程序找到一个好的结构。

这是问题的基本思想:应该有侧导航菜单组件和一个包含路由器插座的内容区域。对于某些路线,侧组件应该包含一个额外的导航组件(例如,用于快速访问的项目列表,其中主要内容区域是“详细视图”)。

Top level template structure:

<sidenav>
  <featureA-nav-fragment></featureA-nav-fragment>
</sidenav>
<router-outlet>
  <!-- featureA component -->
</router-outlet>

菜单应该是一个独立于任何其他组件或功能区域的组件,并且不应该知道额外的导航组件,但它应该包装这个组件。

一种实现方式是仅定义顶级组件,并在由路由定义的每个屏幕中提供 HTML 模板中的侧边菜单。在我看来,这是一个糟糕的设计,因为部分 HTML 代码是重复的。

另一种选择是在菜单组件中的活动路线上创建一个开关,并在那里包含正确的导航片段,但这会将路线(屏幕)的逻辑传播到几个组件中,这对我来说似乎是一个更糟糕的设计。

为导航片段使用命名路由器插座也不是正确的方法,因为组件不是彼此独立显示,而是始终在一起显示。手动修改路线(清除导航片段部分)会破坏设计。

我还没有设法在角度文档中为这种用例找到一个好的设计。我在这里错过了什么吗?

4

1 回答 1

0

我终于自己找到了一个可行的解决方案。

如果您遇到某些组件应该将其模板内容的一部分注入另一个组件的问题,您可能希望将结构指令与自定义路由器服务一起使用。

这种模式的总体思路是在主视图组件(上面的 featureA 组件)的模板中使用特殊的结构指令。

<div *embeddedIntoNav>some navigation related content</div>   
<div>
  Feature A view
<div>

该指令是通过将模板引用转发到自定义路由器服务来实现的。

@Directive({
  selector: '[embeddedIntoNav]'
})
export class EmbeddedIntoNavDirective {

  constructor(
    private customRouter: CustomRouter,
    private templateRef: TemplateRef<any>
  ) { }

  ngOnInit() {
    this.customRouter.navContent$.next(this.templateRef);
  }

  ngOnDestroy() {
    this.customRouter.navContent$.next(null);
  }
}

用这个结构指令标记的部分不附加到特征 A 的子节点,而只是转发到路由器。路由器实现只是每个嵌入式视图出口的一组 BehaviorObservables。

另一个指令用于定义嵌入式视图的出口:

@Directive({
  selector: 'nav-container'
})
export class NavContainerDirective implements OnInit {

  constructor(
    private viewContainer: ViewContainerRef,
    private customRouter: CustomRouter
  ) {
  }

  ngOnInit() {
    this.customRouter.navContent$.subscribe((template) => {
      this.viewContainer.clear();
      if (template) {
        this.viewContainer.createEmbeddedView(template);
      }
    });
  }
}

使用这种模式,您可以构建注入多个视图的路由器,只需触摸一个文件并将逻辑全部保存在一个地方。

于 2017-05-15T05:11:01.170 回答