创建基于条件加载特定组件的路由路径



我想为类似的结构化路径加载不同的组件。

手段

example.com/whatever-post-slug --> 加载后组件
example.com/whatever-page-slug -->加载页面组件
example.com/hello-i-am-a-string -->加载后组件(因为 slug 属于一个帖子(example.com/about-us --> 加载页面组件(因为该 slug 属于一个页面(

我为什么要这样做?

有人可能会想:嘿,但你为什么不定义两条前缀不同的路径,这就是路径的用途呢?

答案是:我正在创建(顺便说一下开源(Angular WordPress主题,我希望路由是用户决定的,而不是强制任何硬编码结构。

在多种可能性之一中,帖子和页面(如果你不了解WordPress,只知道这是我想使用独立模块和组件的两种不同的内容类型(可以在根级别共享蛞蝓。

乍一看,我不知道该 slug 是属于帖子还是页面或其他东西(所以UrlMatcher在这里无能为力(。

我想到解决方案了吗?

是的,三个。

第一个解决方案

我可以创建一个将加载 catchall 路由的包装器组件,然后,在这个组件中执行以下操作:

<whatever-a-component *ngIf="showComponentA()"><whatever-a-component>
<whatever-b-component *ngIf="showComponentB()"></whatever-b-component>

并让包装器组件完成所有逻辑。

这会在游戏中添加一个额外的中间组件。

第二种解决方案

使用解析程序进行捕获,然后在解析器中执行所有逻辑。

问题是,我需要订阅 http 通信才能知道我正在处理哪种内容类型,并且由于解析器 resolve(( 方法需要返回一个 Observable,因此在那里订阅并不好。

当然,如果我返回一个等待一段时间的可观察占位符,它也可以工作,如下所示:

// ... inside resolve()
// Force an observable return to allow suscriptions take their time
return Observable.create(observer => {
setTimeout(() => {
console.log("Resolver observable is done");
observer.complete();
}, 15000);
});

。或者如果我用mergeMap()管道我的订阅并在从订阅中获取结果时返回 EMPTY。

一旦我取回了我的数据,我就可以设置新的路由,包括必须指向其特定组件的当前路径。

对我来说,这似乎不是一种非常干净的方法。

第三种解决方案

只需加载一个普通的调度程序组件,该组件将在OnInit()处执行所有检查,然后导航到特定于"秘密"组件的 url,但使用{ skipLocationChange: true },因此用户将拥有正确的路由,并且还将加载正确的组件。

但同样,这在游戏中增加了一个额外的中间组件。

我认为这是最干净的解决方案,因为在应用程序路由模块中,我可以执行以下操作:

{
path: 'wp-angular/view-post/:id',
loadChildren: () => import('./view-post/view-post.module').then(m => m.ViewPostModule)
},
{
path: 'wp-angular/view-page/:id',
loadChildren: () => import('./view-page/view-page.module').then(m => m.ViewPageModule)
}

因此,仅当用户实际访问这两种内容类型之一时,我才会延迟加载这些模块。

此外,如果用户随后访问相同类型的第二个内容,则该内容类型组件将已可用。

而且我可以使用{ skipLocationChange: true }的事实将使保持路径符合预期成为可能。

此外,这允许显示导航加载反馈,而无需订阅路由器事件。

问题

你会怎么做,为什么?

也许我缺少一些神奇的 Angular 功能,该功能允许以直截了当的方式执行此操作。

有一次我遇到了类似的问题,我像这样解决:

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

代码可能是这样的:

处理程序模块

@NgModule({
declarations: [],
imports: [
CommonModule,
RouterModule
],
providers: [
{
provide: ROUTES,
useFactory: configHandlerRoutes,
deps: [CustomService],
multi: true
}
]
})
export class HandlerModule {}
export function configHandlerRoutes(customService: CustomService) {
let routes: Routes = [];
if (customService.whatever()) {
routes = [
{
path: '', component: AComp
}
];
} else {
routes = [
{
path: '', component: BComp
}
];
}
return routes;
}

然后在 AppRoutingModule 中,路径 '' 的模块将是 HandlerModule:

// AppRoutingModule
{
path: '',
loadChildren: () => import('app/handler/handler.module').then(mod => mod.HandlerModule)
}

在自定义服务中,当提供方法.whatever((的值更改时,您必须更新Router.config,因为应用程序将仅加载首次加载的组件。这是因为 useFactory 提供程序在 HandlerModule 中使用的函数"configHandlerRoutes"仅在我们第一次导航到 " 路径时执行,之后,Angular 路由器已经知道他必须加载哪个组件。

总之,在海关服务中,您必须执行以下操作:

export class CustomService {
private whateverValue: boolean;
constructor(private router: Router) {
}
public whatever(): boolean {
return this.whateverValue;
}
public setWhatever(value: boolean): void {
const previous = this.whateverValue;
this.whateverValue = value;
if (previous === this.whateverValue) {
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

相关内容

  • 没有找到相关文章

最新更新