前言待会再续,先进入主题吧
如果你试图进入Angular官网学习Routes
,那丰富的属性只会让你望而却步,越读越懵。不如咱们从最简单的开始,一点点剖析Angular的路由模块吧。
最常见的路由配置
使用route对象的path
,component
属性,偶尔用到redirect
和patchMatch
,或许你就已经能够胜任很多场景下的路由跳转了。 首先我们在新建一个Angular项目时,ng new my-first-router
时,CLI会自动问你是否需要为你添加路由模块,输入y
即可
如果你记忆超群,不如记一下下面的命令行,直接一步到位 ng new my-first-router --routing
,这样做的好处就是生成一个app-routing.module.ts
的文件,并且自动import到AppModule
上。
在开始之前,让我们清空一下app.component.html
文件,仅留下最后一行的<router-outlet></router-outlet>
。
现在打开我们的app-routing.module.ts文件,找到下面这行代码:
js
const routes: Routes = [];
这将是我们接下来的主战场,下面我们来设想几个场景,我将以本地项目为例子:
-
假设我们默认启动的项目URL为
localhost:4200
,但是我的主页面路径为localhost:4200/home
,有什么办法让用户输入localhost:4200
就能自动跳转到home
路径吗?答 :使用
redirectTo
,即当路径匹配的时候重定向到redirectTo指定的路径:
js
const routes: Routes = [{
path: '',
redirectTo: 'home',
pathMatch: 'full'
},
{
path: 'home',
component: HomeComponent
}];
解析 : 'localhost:4200'
后面没有任何字符,所以我们用path:''
去匹配,一旦匹配上,就将url改成'localhost:4200/home'
,随后路径中的home
字符串又匹配上了path:'home'
,因此在AppComponent
Html文件中的<router-outlet>
标签里将会出现HomeComponent
中的内容。(注意:文中提到的component请自行通过ng g component xxx
生成,就不重复描述了),请注意上段代码的第四行 patchMatch:'full'这个是必须要的,后面会详细解释,咱们先留个小疑问。(挖坑)
- 如果我输入了一个没有匹配上的路径,会发生什么?如何控制它呢?
答 :当输入一个不存在的路径时,系统会自动重定向到项目原始路径"localhost:4200"
,如果想捕捉这类未匹配的路径我们可以巧用通配符path:"**"
去匹配一切路径,做一个兜底方案。
js
const routes: Routes = [{
path: '',
redirectTo: 'home',
pathMatch: 'full'
},
{
path: 'home',
component: HomeComponent
},
{
path: '**',
component: NotFoundComponent
}
];
试图在浏览器中输入localhost:4200/testPath
,你会看到not-found works!
的字样,说明NotFoundComponent
被加载显示了,path:'**'
捕捉到了testPath
路径。
但是使用上面的通配符,切记一点需要把它放在所有的路径配置的最下面,因为Angular是从上往下去匹配路径的,一旦匹配上**
就直接去NotFound了,下面配置的所有路径都不再生效啦,切记切记!
有了上面的基础知识,其实一级路径都可以轻松配置啦。但是二级路径又要如何配置呢?
配置子路由 Children属性
children
属性其实也是一个Routes
对象,所以上面说到的属性也可以重复使用。假设我有一个ParentComponent
,FirstChildComponent
,SecondChildComponent
。Parent
中有Section A
是我无论如何都要显示的,Section B
则是根据路由控制的,例如'parent/first-child'
路径下,我想在Section B
中显示 first-child works! ; 'parent/second-child'
路径下我则想显示second child works! 该怎么去配置这个路由呢?
当你想要通过路由控制某一个部位的显示内容的时候,首先在该部位放入<router-outlet></router-outlet>
parent.component.html
<!--Section A-->
<p>parent works!</p>
<!--Section B-->
<router-outlet></router-outlet>
然后在app-routing.module.ts
文件中加入下面片段:
js
...
{
path: 'parent',
component: ParentComponent,
children: [
{
path: 'first-child',
component: FirstChildComponent
},{
path: 'second-child',
component: SecondChildComponent
}
]
},
...
运行结果:
一个简单有效的子路由就实现啦! 关于子路由后面还有懒加载
之类的知识,先不在这里多阐述了,有机会再慢慢整理。
详细讲一下pathMatch
当你有了子路由的知识以后,我就可以引入pathMatch的概念了,该属性在Angular官方文档中是这样说的 路径匹配策略,为 "prefix" 或 "full" 之一。默认为"prefix"。
再往后的内容无论中英文版本我都读不懂,就不再贴出来了。我开始试图理解这个属性,很明显prefix
是前缀的意思,full
肯定是它的反之,我结合官方文档中蹩脚的解释猜测,是不是设置成prefix的路径,只要是前半段符合,则自动匹配上;而设置成full的则必须完全匹配; 我试图用localhost:4200/homeTest
和localhost:4200/home/test
去验证我的想法,很不幸我都被带到了not-found页面,说明他们都没有被 {path:'home', pathMatch:'prefix'*默认值*}
捕捉到。
再次研读一下官网信息,有一句话给了我启发例如,如果路由的子项(children)之一与段"user"匹配,则认为"/team/11/user"与前缀"team/:id"匹配。
也就是说team/:id
被认为是prefix前缀
。当解析/team/11/user
时,由于/team/11
符合前缀team/:id
,因此angular引擎会继续进入该路径的children属性中查找是否有匹配user
的子路由,一旦找到,路由即匹配成功。一切似乎变的合理起来。下面只需要写个例子证明这一猜想,我将创建PathMatchComponent
, PrefixComponent
,在pathMatch.component.html
中放置<router-outlet></router-outlet>
, 并且设置以下路由参数:
js
...
{
path: 'pathMatch',
component: PathMatchComponent,
children:[
{
path: 'prefix',
component: PrefixComponent
}
],
pathMatch: 'prefix' /**默认值 */
},
...
运行结果:
到这里其实并没有特别,就是一个简单的子路由实现,但是当你试图将patchMatch
改成full
,你会发现not-found
页面出现了,至此patchMatch之谜终于揭开了。用我自己的话解释就是,这个字段决定了当前定义的这个route
里的路径path
是否支持片段式匹配
,即一个路径/pathMatch/prefix
是否可以通过前缀匹配
先进入到path:'pathMatch'
一级路由中,再去它的children二级路由中查找剩下的'/prefix'
路径,当然如果还是没找到匹配项的话,依然会被not-found捕捉到。但如果我们设置pathMatch:'full'
,则表示不支持二级路由匹配,必须在当前路由中直接找到匹配的path。这就是为啥上面的例子一旦改成full
模式,/pathMatch/prefix
不再完全匹配path:'patchMatch'
,因此被判别为无匹配路由,从而进入not-found。
如果你真正的理解了pathMatch
,或许你就能明白为什么下面的路径强调必须要开启full
模式了吧?(填坑)
js
const routes: Routes = [{
path: '',
redirectTo: 'home',
pathMatch: 'full'
},
因为任何的路径我们都可以认为是path:''
的子路由,如果还是允许前缀匹配的话,任何路由都会被path:''
捕捉再被redirectTo
属性带走,谁也别想去自己的路径配置里去。(统统毁灭吧!--发疯文学 :p)
至此,一个简单的Angular Routes算是解释清楚了,其他的属性我们留到下一篇吧~