Angular 5 - 对不同模块使用相同的路径

标签 angular angular5 server-side-rendering angular-universal

如果你们碰巧是 Facebook 用户,您可能会注意到,当用户登录或注销时,网址“ https://www.facebook.com ”不会改变。我在正在构建的应用程序中遇到了同样的问题(使用 Angular 5)。尽管有一些建议的解决方案:

  1. 首先是使用相同的路由,一个组件(例如:home),在 home 的模板中我们使用 *ngIf 插入 in,out (组件),在运行时我们检查用户是否登录或退出,并在此基础上,我们显示相应的(输入或输出)组件。

home.component.html

<app-in *ngIf="loggedIn"></app-in>
<app-out *ngIf="!loggedIn"></app-out>
  • 我认为第二种方法会更干净,特别是在使用延迟加载时,是连续使用两个具有相同空路径的路由,并使用<保护(例如:第一个) strong>ma​​tcher,现在说实话,这仍然很丑陋,因为 matcher 不适合这种高级用法(它也是同步的,并且没有包装在服务中 - 例如 canLoadcanActivate..etc- 可以轻松地注入(inject)一些其他服务(例如:authService)来检查是否登录或注销)。
  • home.routing.ts

    .
    .
    .
    
    const routes: Routes = [
      {
        matcher: matcherFunc,
        loadChildren: './in/in.module#InModule'
      },
      {
        path: '',
        loadChildren: './out/out.module#OutModule'
      }
    ];
    
    .
    .
    .
    

    这是匹配器函数:

    export function matcherFunc(url: UrlSegment[]) {
      let currentUser;
    
    
        currentUser = localStorage.getItem('user');
    
      if (url.length === 0 && currentUser) {
        return ({ consumed: url });
      } else {
        return null;
      }
    }
    

    当我将应用程序升级为通用时,问题变得更加严重,因为在这种情况下,我必须在服务器端处理全局变量(窗口、本地存储等) 我完全被困住了!

    我相信这个问题已经存在了一段时间,但没有令人满意的答案,有什么建议吗?

    最佳答案

    您可以使用一个模块来处理应该加载的模块,方法是使用 Angular 的 useFactory 提供程序提供 RouterModule 的 ROUTES。

    代码可能是这样的。

    // HandlerModule
    
    @NgModule({
      declarations: [],
      imports: [
        CommonModule,
        RouterModule
      ],
      providers: [
        {
          provide: ROUTES,
          useFactory: configHandlerRoutes,
          deps: [SessionService],
          multi: true
        }
      ]
    })
    
    
    export class HandlerModule {}
    
    export function configHandlerRoutes(sessionService: SessionService) {
      let routes: Routes = [];
      if (sessionService.isLoggedIn()) {
        routes = [
          {
            path: '', loadChildren: './in/in.module#InModule'
          }
        ];
      } else {
        routes = [
          {
            path: '', loadChildren: './out/out.module#OutModule'
          }
        ];
      }
      return routes;
    }
    

    然后在您的 AppRoutingModule 中,路径 '' 的模块将成为 HandlerModule:

    // AppRoutingModule
    
     {
        path: '',
        loadChildren: './handler/handler.module#HandlerModule'
     }
    

    在SessionService之后,当提供方法isLoggedIn的值发生变化时,您必须更新Router.config,因为应用程序只会加载第一次加载的页面(模块)。这是因为 HandlerModule 中 useFactory 提供程序使用的函数“configHandlerRoutes”仅在我们第一次导航到“”路径时执行,之后 Angular Router 已经知道他必须加载哪个模块。

    总而言之,在 SessionService 中您必须执行以下操作:

      export class SessionService {
      private loggedIn: boolean;
      constructor(private router: Router) {
        this.loggedIn = false;
      }
    
      public isLoggedIn(): boolean {
        return this.loggedIn;
      }
    
      public setLoggedIn(value: boolean): void {
        const previous = this.loggedIn;
        this.loggedIn = value;
        if (previous === this.loggedIn) {
          return;
        }
        const i = this.router.config.findIndex(x => x.path === '');
        this.router.config.splice(i, 1);
        this.router.config.push(
          {path: '', loadChildren: () => import('app/handler/handler.module').then(mod => mod.HandlerModule)}
        );
      }
    }
    

    就是这样。

    如果您想要另一个引用,这里有一篇文章,他们使用相同的方法:https://medium.com/@german.quinteros/angular-use-the-same-route-path-for-different-modules-or-components-11db75cac455

    关于Angular 5 - 对不同模块使用相同的路径,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49193541/

    相关文章:

    leaflet - 如何将 Leaflet 集成到 Angular 5 中

    没有对话框组件类的 Angular Material viewchild 对话框

    javascript - Angular5可以激活守卫:Types of property 'canActivate' are incompatible

    Angular/Rxjs 管道异步不适用于 ssr?

    node.js - 浏览器返回 403 访问错误,可能由 AWS 引起

    angular - 如何在 Angular 5 View 中访问枚举值

    Angular 2 Component监听服务变化

    node.js - 引用错误 : window is not defined Angular Universal

    html - 显示真棒字体 - Angular 2

    angular - 无法读取属性 - displayWith