Angular 带有路由参数的前缀路由

Angular routing for prefix with route parameter

我想实现用户个人资料页面。使用

会很简单

/profile/user123 路径使用:

app-routing.module

{
  path: 'profile',
  loadChildren: () => import('./modules/profile/profile.module').then(m => m.ProfileModule)
},

简介-routing.module

{
  path: ':username',
  component: ProfileComponent
},

但是,我想做一些花哨的事情 URL,比如 /@user123

不幸的是,我没有找到任何关于如何做的线索。我尝试了以下方法:

app-routing.module

{
  path: '@:username',
  loadChildren: () => import('./modules/profile/profile.module').then(m => m.ProfileModule)
},

简介-routing.module

{
  path: '',
  component: ProfileComponent
},

但是没用。

我只想到一件事,那就是使用 Guard 检查 '@' 前缀,否则重定向到 /not-found 页面。

关于如何使用“Angular”方式进行路由的任何想法?

您可以使用自定义路由 matcher 来达到预期的效果。

  • app-routing.module.ts
    {
      path: 'profile',
      loadChildren: () => import('./modules/profile/profile.module').then(m => m.ProfileModule)
    },
  • profile-routing.module.ts 中,您可以通过提供 custom URL-matching function 来指定路由:
    {
      matcher: (url) => {
        // You can have regex as per your requirement
        if (url.length === 1 && url[0].path.match(/^@[\w]+$/gm)) {
          return {
            consumed: url,
            posParams: {
              username: new UrlSegment(url[0].path.substr(1), {}) // <--- creating UrlSegment by getting rid of @ from url path
            }
          };
        }
    
        return null;
      },
      component: ProfileComponent
    }
  • profile.component.ts 文件中,您可以将 username 读取为:
    username$!: Observable<string | null>;
    constructor(private activatedRoute: ActivatedRoute) { }

    ngOnInit(): void {
      this.username$ = this.activatedRoute.paramMap
        .pipe(
          map((params: ParamMap) => params.get('username'))
        );
    }
  • profile.component.html 中,您可以将用户名打印为:
    <p>
        Profile: {{username$ | async}}
    </p>
  • 现在只需导航至 url /profile/@user123,您应该能够在 ProfileComponent
  • 中获得 user123 作为用户名

Siddhant 提供的解决方案非常好,但我想要 /@user123 而不是 /profile/@user123,所以我稍微调整了一下。

app-routing.module.ts

{
  matcher: (url) => {
    if (url.length === 1 && url[0].path.match(/^@[\w.\-]+$/gm)) { // <--- added a hyphen and a dot, since \w only does [a-zA-Z0-9_]
      return {
        consumed: url,
        posParams: {
          username: new UrlSegment(url[0].path.substr(1), {}) // <--- creating UrlSegment by getting rid of @ from url path
        }
      };
    }
    return null;
  },
  loadChildren: () => import('./modules/profile/profile.module').then(m => m.ProfileModule)
},

个人资料。routing.module.ts

{
  path: '',
  component: ProfileComponent
},

profile.component.ts

ngOnInit(): void {
  this.activatedRoute.paramMap.subscribe(paramMap => {
    this.userService.getUser(paramMap.get('username')).subscribe(res => {
      if (res) {
        this.user = res;
      } else {
        this.router.navigate([Utils.ARTICLE_NOT_FOUND_URL]);
      }
    });
  });
}

我正在添加另一个答案,因为我还需要使用 @user123/edit 路径,但它不适用于原始解决方案。所以这是如何做到的:

app-routing.module.ts

 {
    matcher: (url) => {
      console.log(url);
      if (url[0].path.match(/^@[\w.\-]+$/gm)) { <-- removed check for url length
        return {
          consumed: url.slice(0, 1), <-- return the rest of the URL instead of the whole URL (this routing rule should only consume @user123 and return the rest of the URL, which is /edit)
          posParams: {
            username: new UrlSegment(url[0].path.substr(1), {}) // <--- creating UrlSegment by getting rid of @ from url path
          }
        };
      }
      return null;
    },
    loadChildren: () => import('./modules/profile/profile.module').then(m => m.ProfileModule)
  },

简介.routing.module.ts

{
    path: '',
    component: ProfileComponent
  },
  {
    path: 'edit',
    component: EditProfileComponent
  },