我想为类似的结构化路径加载不同的组件。
意味着:
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。
乍一看,我不知道 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 功能,它允许以直截了当的方式做到这一点。