使用angular的router.navigate()
方法进行跳转页面的时候,我们传值的方式有两种:
- 使用链接参数数组:
router.navigate(['/a', {code: '123'}])
。构造的链接为/a;code=123
. - 使用查询参数:
router.navigate(['/b'], {queryMap: {code: '123'}})
。构造的链接为:/b?code=123
.
那么这两种传参方式的关系和区别是啥?我们该如何在正确的场景使用这正确的方法?来研究研究。
paramMap
一个Observable
,其中包含一个由当前路由的必要参数和可选参数组成的map
对象。用这个map
可以获取来自同名参数的单一值或多重值。
首先要区分下必选参数和可选参数。这涉及到路由的定义
必选参数
如何定义一个必选参数:
1 | { |
上面这样就创建了一个包含必选参数id
的路由了,这个路由中的:id
等于是在路径中创建了一个空位,这个空位不补全是没法导航的:
1 | this.router.navigate(['/a']); // 跳转错误,无效路由 |
可选参数
可选参数是在导航期间传送任何复杂信息的理想载体,可选参数不涉及到模式匹配并在表达式上提供了巨大的灵活性。那如何传递一个可选参数:
1 | this.router.navigate(['/a', {a: 1, b: 2}]); |
上面这种方式跳转的时候,会生成跳转链接:/a;a=1;b=2
,对于路由/a
来讲,对象里面的a
和b
是可选参数的key。这是通过js来跳转,同样的直接通过页面跳转可以直接写成:
1 | <a [routerLink]="['/a', {a: 3, b=2}]">B page</a> |
具有同样的效果。
注意:这里数组里的对象只可以是一层,不可以多层。这里转换的方式为第一层对象的key,值会直接转为string。所以,如果是多层对象的话会直接转成[object object]
,其他比如null也会直接转换为字符串null
上面了解了必选参数和可选参数的声明和使用,页面跳转到对应的目标页面后我们需要去获得这些参数,这时候就需要用到paramMap
了。
首先它是一个Observable,那么我们可以通过Observable的方式来拿。
1 | this.activateRouter.paramMap.pipe( |
ActivatedRoute.paramMap
属性是一个路由参数的可观察对象,当用户导航到这个组件时,paramMap会发射一个新的值,我们可以在ngOnInit
中订阅拿到我们的参数。
这里为什么要加switchMap
操作符?可以参考:rxjs操作符-switchMap.
当然,可以使用“快照”(snapshot)的方式获取参数:
1 | this.activateRouter.snapshot.paramMap.get('a'); |
通过快照的方式获取的参数是不需要Observable时的一个简写。这种情况你要保证该url只会用一次(即不会发生从当前url导航到当前url的情况)。因为使用这种方式获取的参数是不会变动的,因为组件的ngOnInit
方法只会调用一次,而如果检测到路由相同而参数不同时,是不会重新初始化组件的。
queryParamMap
一个Observable,其中包含一个对所有路由都有效的查询参数组成的map对象。用这个map可以获取来自查询参数的单一或多重值。
如何产生一个查询参数?
使用navigate
方法的第二个参数,来看看navigate
方法的定义:
1 | navigate(commands: any[], extras?: NavigationExtras): Promise<boolean>; |
可以知道第二个参数是导航附加功能,里面有个参数queryParams
可以为我们的路由加上查询参数:
1 | this.router.navigate(['/b', {a: 33], { |
上面的例子里面,我们的跳转后的链接为:/b;a=33?code=bbb
,a=33
这个是可选参数,不用管,code=bbb
才是我们需要的查询参数。
和其他参数不同,查询参数是可以在当前url中全部有效(包括子页面、service等其他部分也可以获取到)。
还可以在导航之间保留查询参数:
1 | // 比如当前的url是在/b;a=33?code=bbb |
这样跳转后的链接为:/a/1?code=bbb
。可以看到查询参数被保留了。
查询参数有更强大的配置,具体可以参见类型定义:NavigationExtras
查询参数的获取
paramMap和queryParamMap的获取方式都一样,都可以通过Observable的方式和快照的方式进行获取,例如:
1 | this.activateRouter.queryParamMap.pipe( |
共同的api
- has(name) 如果参数名位于参数列表中,就返回 true 。
- get(name) 如果这个 map 中有参数名对应的参数值(字符串),就返回它,否则返回 null。如果参数值实际上是一个数组,就返回它的第一个元素。
- getAll(name) 如果这个 map 中有参数名对应的值,就返回一个字符串数组,否则返回空数组。当一个参数名可能对应多个值的时候,请使用 getAll。
- keys 返回这个 map 中的所有参数名组成的字符串数组。
paramMap和queryParamMap的最大的区别就是,paramMap是针对于当前url,哪怕是当前url的子页面也无法获取到当前页面的参数。而queryParamMap是对所有路由都有效的查询参数,在使用上需要应对不同情况进行选择。一般使用都是针对于当前路由的,需要全局都有效的很少情况,所以一般还是使用paramMap,特殊情况采用queryParamMap。