RouterLink 指令简介
RouterLink 指令可以让你链接到应用程序的特定部分。若链接是静态的,我们可以按照以下的方式,来使用该指令:
link to user component
如果你需要使用动态值生成链接地址,你可以传递一个路径片段 (segments) 的数组,然后再传递每个段的参数。例如使用 ['/team', teamId, 'user', userName, {details: true}]
数组,意味着我们想要生成一个链接到 /team/11/user/bob;details=true
。
多个静态段 (segments) 能够被合并为一个,例如 ['/team/11/user', userName, {details: true}]
。
第一个路径片段可以以 /
,./
或 ../
开头:
如果以
/
开头,路由将从根路由开始查找如果以
./
开头或没有使用/
,则路由将从当前激活路由的子路由开始查找如果以
../
开头,路由往上一级查找
你可以使用以下方式设置查询参数和片段 (fragment):
link to user component
RouterLink 指令将基于以上设定的输入参数,生成如下链接:/user/bob#education?debug=true
。此外我们可以通过 queryParamsHandling
属性来声明如何处理查询参数,可用的选项是:
merge - 合并已有的
queryParams
到当前的queryParams
中preserve - 保存当前的
queryParams
default ('') - 仅使用查询参数
具体使用示例如下:
link to user component
RouterLink 指令详解
RouterLink 指令定义
@Directive({selector: ':not(a)[routerLink]'})
RouterLink 指令输入属性
// 设置URL相关的查询参数
@Input() queryParams: {[k: string]: any};
// 设置URL上的hash fragment
@Input() fragment: string;
// 设置查询参数处理方式:merge、preserve 、default
@Input() queryParamsHandling: QueryParamsHandling;
// 设置是否保留fragment
@Input() preserveFragment: boolean;
// 设置页面导航时,是否把新的状态添加到历史记录中
@Input() skipLocationChange: boolean;
// 设置页面导航的同时,是否替换历史记录中的当前状态
@Input() replaceUrl: boolean;
// 设置commands参数信息,如:['/user/bob']
@Input()
set routerLink(commands: any[]|string) {
if (commands != null) {
this.commands = Array.isArray(commands) ? commands : [commands];
} else {
this.commands = [];
}
}
RouterLink 指令绑定
事件绑定
// 监听RouterLink指令宿主元素的click事件,进行页面切换
@HostListener('click')
onClick(): boolean {
const extras = {
skipLocationChange: attrBoolValue(this.skipLocationChange),
replaceUrl: attrBoolValue(this.replaceUrl),
};
this.router.navigateByUrl(this.urlTree, extras);
return true;
}
// 转化设置的属性值为bool值
function attrBoolValue(s: any): boolean {
return s === '' || !!s;
}
RouterLink 类的构造函数
export class RouterLink {
constructor(
private router: Router,
private route: ActivatedRoute,
@Attribute('tabindex') tabIndex: string,
renderer: Renderer, el: ElementRef) {
if (tabIndex == null) {
renderer.setElementAttribute(el.nativeElement, 'tabindex', '0');
}
}
}
@Attribute()
@Attribute('attributeName') 装饰器:用于获取指令宿主元素上 attributeName
属性名对应的属性值。
tabindex
tabindex 属性规定元素的 tab 键控制次序 (当 tab 键用于导航时)。
以下元素支持 tabindex 属性:, ,
。
tabindex 语法:
RouterLink 类的属性
// 用于保存commands参数信息
private commands: any[] = [];
// 标识是否保存查询参数,4.0.0版本后用queryParamsHandling代替
private preserve: boolean;
RouterLink 类的方法
// 获取routerLink上配置信息对应的UrlTree
get urlTree(): UrlTree {
return this.router.createUrlTree(this.commands, {
relativeTo: this.route,
queryParams: this.queryParams,
fragment: this.fragment,
preserveQueryParams: attrBoolValue(this.preserve),
queryParamsHandling: this.queryParamsHandling,
preserveFragment: attrBoolValue(this.preserveFragment),
});
}
// angular\packages\router\src\router.ts
// 创建UrlTree
createUrlTree(
commands: any[],
{relativeTo, queryParams, fragment,
preserveQueryParams, queryParamsHandling,preserveFragment}:
NavigationExtras = {}): UrlTree {
if (isDevMode() && preserveQueryParams && console && console.warn) {
console.warn('preserveQueryParams is deprecated, use queryParamsHandling instead.');
}
const a = relativeTo || this.routerState.root;
const f = preserveFragment ? this.currentUrlTree.fragment : fragment;
let q: Params|null = null;
// 根据queryParamsHandling属性值,处理查询参数
if (queryParamsHandling) {
switch (queryParamsHandling) {
case 'merge':
q = {...this.currentUrlTree.queryParams, ...queryParams};
break;
case 'preserve':
q = this.currentUrlTree.queryParams;
break;
default:
q = queryParams || null;
}
} else {
q = preserveQueryParams ? this.currentUrlTree.queryParams : queryParams || null;
}
return createUrlTree(a, this.currentUrlTree, commands, q !, f !);
}
RouterLinkWithHref 指令详解
RouterLinkWithHref 指令定义
@Directive({selector: 'a[routerLink]'})
RouterLinkWithHref 指令输入属性
// 设置a标签target的值
@Input() target: string;
// 设置URL相关的查询参数
@Input() queryParams: {[k: string]: any};
// 设置URL上的hash fragment
@Input() fragment: string;
// 设置查询参数处理方式:merge、preserve 、default
@Input() queryParamsHandling: QueryParamsHandling;
// 设置是否保留fragment
@Input() preserveFragment: boolean;
// 设置页面导航时,是否把新的状态添加到历史记录中
@Input() skipLocationChange: boolean;
// 设置页面导航的同时,是否替换历史记录中的当前状态
@Input() replaceUrl: boolean;
// 设置commands信息,如:['/user/bob']
@Input()
set routerLink(commands: any[]|string) {
if (commands != null) {
this.commands = Array.isArray(commands) ? commands : [commands];
} else {
this.commands = [];
}
}
RouterLinkWithHref 指令绑定
属性绑定
@HostBinding('attr.target') @Input() target: string;
@HostBinding() href: string;
标签定义超链接,用于从一个页面链接到另外一个页面。
标签中有两个重要的属性:
href - 规定链接指向的页面的 URL 地址。如果不使用 href 属性,则不可以使用如下属性:download, media, rel, target 以及 type 属性。
-
target - 规定链接的页面在浏览器窗口中的打开方式,它的参数值主要有:
事件绑定
// 监听RouterLink指令宿主元素的click事件,进行页面切换
@HostListener('click', ['$event.button', '$event.ctrlKey', '$event.metaKey'])
onClick(button: number, ctrlKey: boolean, metaKey: boolean): boolean {
if (button !== 0 || ctrlKey || metaKey) {
return true;
}
if (typeof this.target === 'string' && this.target != '_self') {
return true;
}
const extras = {
skipLocationChange: attrBoolValue(this.skipLocationChange),
replaceUrl: attrBoolValue(this.replaceUrl),
};
this.router.navigateByUrl(this.urlTree, extras);
return false;
}
MouseEvent 表示用户与指针设备 (如鼠标) 交互时发生的事件,常见的事件包括:click、dblclick、mouseup 与 mousedown 事件。其中 MouseEvent 对象中包含一个 button
属性,用于表示用户按下的鼠标按键,可能的属性值如下:
0 - 主按键被按下,通常指鼠标左键。
1 - 辅助按键被按下,通常指鼠标滚轮。
2 - 次按键被按下,通常指鼠标右键。
3 - 第四个按钮被按下,通常指浏览器后退按钮。
4 - 第五个按钮被按下,通常指浏览器的前进按钮。
对于配置为左手使用的鼠标,按键操作将正好相反。此种情况下,从右至左读取值。在上面示例代码中,我们还访问了 MouseEvent
对象的 ctrlKey
和 metaKey
属性,此外除了这两个属性外 MouseEvent
对象中还包含 altKey
和 shiftKey
属性。这些属性的相关说明如下:
MouseEvent.ctrlKey - 当鼠标事件触发时,如果
control
键被按下,则返回 true。MouseEvent.metaKey - 当鼠标事件触发时,如果 (Window -
⊞
,Mac -⌘ Command
) 键被按下,则返回 true。MouseEvent.altKey - 当鼠标事件触发的时候,如果 (Window -
alt
,Mac -Option
或⌥
) 键被按下,返回true。MouseEvent.shiftKey - 当鼠标事件触发时,如果
shift
键被按下,则返回 true。
若按下 ctrlKey
,再点击 标签,则会使用当前的 URL 地址,新建一个新的 tab 页。若按下
metaKey
,再点击 标签,则会重新刷新当前页。因此在
onClick()
方法中,才会执行相应的判断。
RouterLinkWithHref 指令生命周期
ngOnChanges()
// 输入属性发生变化时,更新a标签href属性
ngOnChanges(changes: {}): any {
this.updateTargetUrlAndHref();
}
ngOnDestroy()
// 指令销毁时,取消路由事件的订阅
ngOnDestroy(): any {
this.subscription.unsubscribe();
}
RouterLinkWithHref 类的构造函数
export class RouterLinkWithHref implements OnChanges, OnDestroy {
constructor(
private router: Router,
private route: ActivatedRoute,
private locationStrategy: LocationStrategy) {
// 订阅路由事件,当页面切换成功后更新a标签的href属性
this.subscription = router.events.subscribe(s => {
if (s instanceof NavigationEnd) {
this.updateTargetUrlAndHref();
}
});
}
}
RouterLinkWithHref 类的属性
// 用于保存commands参数信息
private commands: any[] = [];
// 用于保存取消订阅路由事件订阅的Subscription对象
private subscription: Subscription;
// 标识是否保存查询参数,4.0.0版本后用queryParamsHandling代替
private preserve: boolean;
RouterLinkWithHref 类的方法
// 获取routerLink上配置信息对应的UrlTree
get urlTree(): UrlTree {
return this.router.createUrlTree(this.commands, {
relativeTo: this.route,
queryParams: this.queryParams,
fragment: this.fragment,
preserveQueryParams: attrBoolValue(this.preserve),
queryParamsHandling: this.queryParamsHandling,
preserveFragment: attrBoolValue(this.preserveFragment),
});
}
// 更新a标签href属性值
private updateTargetUrlAndHref(): void {
this.href = this.locationStrategy
.prepareExternalUrl(this.router.serializeUrl(this.urlTree));
}
RouterLinkActive 指令简介
RouterLinkActive 指令允许你在链接的路由变为活动状态时向元素添加 CSS 类。请看一下以下示例:
Bob
当 URL 地址是 /user
或 /user/bob
时,active-link
类将会被添加到 标签上。如果 URL 发生变化,则
active-link
类将自动从 标签上移除。你也可以一次性添加多个类,具体如下:
Bob
Bob
在应用 routerLinkActive
指令时,你也可以通过 routerLinkActiveOptions
参数,来配置 URL 的匹配方式,具体如下:
Bob
当配置了 {exact: true}
参数,仅当 URL 地址完全匹配时,active-link
类才会被添加到 标签上。此外你可以将
RouterLinkActive
实例分配给模板变量,并直接检查指令的 isActive
状态:
Bob {{ rla.isActive ? '(already open)' : ''}}
最后,你也可以将 RouterLinkActive 指令应用于 RouterLink 的父级元素。具体示例如下:
在上面示例中,当 URL 的地址为 /user/jim
或 /user/bob
时,active-link
类会被添加到对应的 RouterLinkActive 指令详解
RouterLinkActive 指令定义
@Directive({
selector: '[routerLinkActive]',
exportAs: 'routerLinkActive',
})
RouterLinkActive 指令输入属性
// 设置处于激活状态时,宿主元素上应用的class信息
@Input()
set routerLinkActive(data: string[]|string) {
const classes = Array.isArray(data) ? data : data.split(' ');
this.classes = classes.filter(c => !!c);
}
// 设置URL地址的匹配方式
@Input() routerLinkActiveOptions: {exact: boolean} = {exact: false};
RouterLinkActive 指令生命周期
ngAfterContentInit()
// 订阅RouterLink或RouterLinkWithHref集合的changes对象,从而自动更新宿主元素的class信息
ngAfterContentInit(): void {
this.links.changes.subscribe(_ => this.update());
this.linksWithHrefs.changes.subscribe(_ => this.update());
this.update();
}
ngOnChanges()
// 输入属性变化时,更新宿主元素的class信息
ngOnChanges(changes: SimpleChanges): void { this.update(); }
ngOnDestroy()
// 指令销毁时,取消路由事件的订阅
ngOnDestroy(): void { this.subscription.unsubscribe(); }
RouterLinkActive 类的构造函数
export class RouterLinkActive implements OnChanges,
OnDestroy, AfterContentInit {
constructor(
private router: Router,
private element: ElementRef,
private renderer: Renderer,
private cdr: ChangeDetectorRef) {
// 订阅路由事件,当页面切换成功后更新宿主元素上的class信息
this.subscription = router.events.subscribe(s => {
if (s instanceof NavigationEnd) {
this.update();
}
});
}
}
RouterLinkActive 类的属性
// 获取RouterLink集合
@ContentChildren(RouterLink, {descendants: true}) links: QueryList
RouterLinkActive 类的方法
// 获取激活状态
get isActive(): boolean { return this.active; }
// 更新宿主元素的class信息
private update(): void {
if (!this.links || !this.linksWithHrefs || !this.router.navigated) return;
const hasActiveLinks = this.hasActiveLinks();
// react only when status has changed to prevent unnecessary dom updates
if (this.active !== hasActiveLinks) {
this.classes.forEach(
c => this.renderer.setElementClass(this.element.nativeElement, c, hasActiveLinks));
Promise.resolve(hasActiveLinks).then(active => this.active = active);
}
}
// 判断是否是激活的链接
private isLinkActive(router: Router): (link: (RouterLink|RouterLinkWithHref)) => boolean {
return (link: RouterLink | RouterLinkWithHref) =>
router.isActive(link.urlTree, this.routerLinkActiveOptions.exact);
}
// 判断RouterLink或RouterLinkWithHref集合中是否含有激活的链接
private hasActiveLinks(): boolean {
return this.links.some(this.isLinkActive(this.router)) ||
this.linksWithHrefs.some(this.isLinkActive(this.router));
}