【发布时间】:2019-10-25 17:35:19
【问题描述】:
我想为相似的结构化路径加载不同的组件。
意思:
example.com/whatever-post-slug --> 加载帖子组件
example.com/whatever-page-slug --> 加载页面组件
example.com/hello-i-am-a-string --> 加载帖子组件(因为 slug 属于一个帖子)
example.com/about-us --> 加载页面组件(因为 slug 属于一个页面)
我为什么要这样做?
可能有人会想:嘿嘿,但是你为什么不直接定义两个前缀不同的路径,路径是干什么用的呢?
答案是:我正在创建(顺便说一下open source)Angular WordPress 主题,我希望路由是用户决定的,而不是强制任何硬编码结构。
在多种可能性之一中,帖子和页面(如果您不了解 WordPress,只需知道这是两种不同的内容类型,我想使用独立的模块和组件)可能会在根级别共享 slug。
乍一看,我不知道 slug 是属于帖子还是页面或其他东西(所以UrlMatcher 在这里无法提供帮助)。
我有没有想到解决办法?
是的,三个。
第一个解决方案
我可以创建一个包装器组件,它将为包罗万象的路线加载,然后,在这个组件内部执行以下操作:
<whatever-a-component *ngIf="showComponentA()"><whatever-a-component>
<whatever-b-component *ngIf="showComponentB()"></whatever-b-component>
并让 Wrapper 组件完成所有逻辑。
这会在游戏中添加一个额外的中间组件。
第二种解决方案
为包罗万象使用解析器,然后在解析器中执行所有逻辑。
问题是,我需要订阅一个 http 通信才能知道我正在处理什么样的内容类型,并且由于 Resolver resolve() 方法需要返回一个 Observable,所以在那里订阅并不好。
当然,如果我返回一个等待一段时间的占位符 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。
一旦我取回我的数据,我就可以设置新的路线,包括必须指向其特定组件的当前路径。
这对我来说似乎不是一个非常干净的方法。
第三种解决方案
只需加载一个普通的 Dispatcher 组件,它将在 OnInit() 进行所有检查,然后导航到一个“秘密”组件特定的 url,但使用 { skipLocationChange: true },因此用户将拥有正确的路由和正确的组件将被加载。
不过,这又在游戏中添加了一个额外的中间组件。
我认为这是最干净的解决方案,因为在 App Routing 模块中我可以执行以下操作:
{
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 功能,它允许以直截了当的方式做到这一点。
【问题讨论】: