路由是Angular應用程式的核心,這篇文章帶大家了解Angular Router,詳細介紹一下navigate()和navigateByUrl()用法的差別。
路由是 Angular 應用程式的核心,它會載入與所請求路由相關聯的元件,以及取得特定路由的相關資料。這允許我們透過控制不同的路由,獲取不同的數據,從而渲染不同的頁面。 【相關教學推薦:《angular教學》】
首先第一件事,我們需要安裝 Angular Router。你可以透過執行以下任一操作來執行此操作:
yarn add @angular/router # OR npm i --save @angular/router
以上命令執行後,將會自動下載@angular/router
模組到node_modules
資料夾中。
我們需要做的最後一件事,是將<base>
標籤新增到我們的index.html 文件中。路由需要根據這個來決定應用程式的根目錄。例如,當我們前往http://example.com/page1
時,如果我們沒有定義應用程式的基礎路徑,路由將無法知道我們的應用程式的託管位址是http:/ /example.com
還是http://example.com/page1
。
這件事操作起來很簡單,只要開啟專案中的index.html
文件,加入對應的<base>
標籤,具體如下:
<!doctype html> <html> <head> <base href="/"> <title>Application</title> </head> <body> <app-root></app-root> </body> </html>
以上設定資訊告訴Angular 路由,應用程式的根目錄是/
。
要使用路由,我們需要在 AppModule 模組中,匯入 RouterModule。具體如下:
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { RouterModule } from '@angular/router'; import { AppComponent } from './app.component'; @NgModule({ imports: [ BrowserModule, RouterModule ], bootstrap: [ AppComponent ], declarations: [ AppComponent ] }) export class AppModule {}
此時我們的路由還無法正常運作,因為我們還未配置應用程式路由的相關資訊。 RouterModule 物件為我們提供了兩個靜態的方法:forRoot()
和forChild()
來設定路由資訊。
#RouterModule.forRoot()
方法用於在主模組中定義主要的路由訊息,透過呼叫該方法使得我們的主模組可以存取路由模組中定義的所有指令。接下來我們來看看如何使用forRoot()
:
// ... import { Routes, RouterModule } from '@angular/router'; export const ROUTES: Routes = []; @NgModule({ imports: [ BrowserModule, RouterModule.forRoot(ROUTES) ], // ... }) export class AppModule {}
我們透過使用const 定義路由的設定訊息,然後把它當作參數呼叫RouterModule.forRoot()
方法,而不是直接使用RouterModule.forRoot([...])
這種方式,這樣做的好處是方便我們在需要的時候導出ROUTES
到其它模組中。
#RouterModule.forChild()
與Router.forRoot()
方法類似,但它只能應用在特性模組中。
友情提示:根模組中使用forRoot()
,子模組中使用forChild()
這個功能非常強大,因為我們不必在一個地方(我們的主模組)定義所有路由資訊。反之,我們可以在特性模組中定義模組特有的路由訊息,並在必要的時候將它們導入我們主模組。 RouterModule.forChild()
的使用方法如下:
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { Routes, RouterModule } from '@angular/router'; export const ROUTES: Routes = []; @NgModule({ imports: [ CommonModule, RouterModule.forChild(ROUTES) ], // ... }) export class ChildModule {}
透過上述範例,我們知道在主模組和特性模組中,路由配置物件的類型是一樣的,差異只是主模組和特性模組中需呼叫不同的方法,來配置模組路由。接下來我們來介紹如何設定 ROUTES
物件。
我們定義的所有路由都是作為 ROUTES 陣列中的物件。首先,為我們的主頁定義一個路由:
import { Routes, RouterModule } from '@angular/router'; import { HomeComponent } from './home/home.component'; export const ROUTES: Routes = [ { path: '', component: HomeComponent } ]; @NgModule({ imports: [ BrowserModule, RouterModule.forRoot(ROUTES) ], // ... }) export class AppModule {}
範例中我們透過 path 屬性定義路由的匹配路徑,而 component 屬性用於定義路由匹配時需要載入的元件。
友誼提示:我們使用path: ''
來符合空的路徑,例如:https://yourdomain.com
配置完路由資訊後,下一步是使用一個名為router-outlet
的指令告訴Angular 在哪裡載入元件。當 Angular 路由匹配到回應路徑,並成功找到需要載入的元件時,它將動態建立對應的元件,並將其作為兄弟元素,插入到 router-outlet
元素中。
在我們AppComponent 元件中,我們可以在任何位置插入router-outlet
指令:
import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: ` <div class="app"> <h3>Our app</h3> <router-outlet></router-outlet> </div> ` }) export class AppComponent {}
我們現在已經建立了應用程式的主路由,我們可以進一步了解路由的其它配置選項。
到目前為止我們已經介紹的內容只是一個開始 ,接下來我們來看看其它一些選項和功能。
Dynamic routes
##如果路由始终是静态的,那没有多大的用处。例如 path: ''
是加载我们 HomeComponent 组件的静态路由。我们将介绍动态路由,基于动态路由我们可以根据不同的路由参数,渲染不同的页面。
例如,如果我们想要在个人资料页面根据不同的用户名显示不同的用户信息,我们可以使用以下方式定义路由:
import { HomeComponent } from './home/home.component'; import { ProfileComponent } from './profile/profile.component'; export const ROUTES: Routes = [ { path: '', component: HomeComponent }, { path: '/profile/:username', component: ProfileComponent } ];
这里的关键点是 : ,它告诉 Angular 路由,:username
是路由参数,而不是 URL 中实际的部分。
友情提示:如果没有使用 : ,它将作为静态路由,仅匹配 /profile/username
路径
现在我们已经建立一个动态路由,此时最重要的事情就是如何获取路由参数。要访问当前路由的相关信息,我们需要先从 @angular/router
模块中导入 ActivatedRoute
,然后在组件类的构造函数中注入该对象,最后通过订阅该对象的 params 属性,来获取路由参数,具体示例如下:
import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; @Component({ selector: 'profile-page', template: ` <div class="profile"> <h3>{{ username }}</h3> </div> ` }) export class SettingsComponent implements OnInit { username: string; constructor(private route: ActivatedRoute) {} ngOnInit() { this.route.params.subscribe((params) => this.username = params.username); } }
介绍完动态路由,我们来探讨一下如何创建 child routes。
实际上每个路由都支持子路由,假设在我们 /settings
设置页面下有 /settings/profile
和 /settings/password
两个页面,分别表示个人资料页和修改密码页。
我们可能希望我们的 /settings
页面拥有自己的组件,然后在设置页面组件中显示 /settings/profile
和 /settings/password
页面。我们可以这样做:
import { SettingsComponent } from './settings/settings.component'; import { ProfileSettingsComponent } from './settings/profile/profile.component'; import { PasswordSettingsComponent } from './settings/password/password.component'; export const ROUTES: Routes = [ { path: 'settings', component: SettingsComponent, children: [ { path: 'profile', component: ProfileSettingsComponent }, { path: 'password', component: PasswordSettingsComponent } ] } ]; @NgModule({ imports: [ BrowserModule, RouterModule.forRoot(ROUTES) ], }) export class AppModule {}
在这里,我们在 setttings 路由中定义了两个子路由,它们将继承父路由的路径,因此修改密码页面的路由匹配地址是 /settings/password
,依此类推。
接下来,我们需要做的最后一件事是在我们的 SettingsComponent 组件中添加 router-outlet
指令,因为我们要在设置页面中呈现子路由。如果我们没有在 SettingsComponent 组件中添加 router-outlet
指令,尽管 /settings/password
匹配修改密码页面的路由地址,但修改密码页面将无法正常显示。具体代码如下:
import { Component } from '@angular/core'; @Component({ selector: 'settings-page', template: ` <div class="settings"> <settings-header></settings-header> <settings-sidebar></settings-sidebar> <router-outlet></router-outlet> </div> ` }) export class SettingsComponent {}
另一个很有用的路由功能是 component-less 路由。使用 component-less 路由允许我们将路由组合在一起,并让它们共享路由配置信息和 outlet。
例如,我们可以定义 setttings 路由而不需要使用 SettingsComponent 组件:
import { ProfileSettingsComponent } from './settings/profile/profile.component'; import { PasswordSettingsComponent } from './settings/password/password.component'; export const ROUTES: Routes = [ { path: 'settings', children: [ { path: 'profile', component: ProfileSettingsComponent }, { path: 'password', component: PasswordSettingsComponent } ] } ]; @NgModule({ imports: [ BrowserModule, RouterModule.forRoot(ROUTES) ], }) export class AppModule {}
此时, /settings/profile
和 /settings/password
路由定义的内容,将显示在 AppComponent 组件的 router-outlet
元素中。
我们也可以告诉路由从另一个模块中获取子路由。这将我们谈论的两个想法联系在一起 - 我们可以指定另一个模块中定义的子路由,以及通过将这些子路由设置到特定的路径下,来充分利用 component-less 路由的功能。
让我们创建一个 SettingsModule 模块,用来保存所有 setttings 相关的路由信息:
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { Routes, RouterModule } from '@angular/router'; export const ROUTES: Routes = [ { path: '', component: SettingsComponent, children: [ { path: 'profile', component: ProfileSettingsComponent }, { path: 'password', component: PasswordSettingsComponent } ] } ]; @NgModule({ imports: [ CommonModule, RouterModule.forChild(ROUTES) ], }) export class SettingsModule {}
需要注意的是,在 SettingsModule 模块中我们使用 forChild()
方法,因为 SettingsModule 不是我们应用的主模块。
另一个主要的区别是我们将 SettingsModule 模块的主路径设置为空路径 (’’)。因为如果我们路径设置为 /settings
,它将匹配 /settings/settings
,很明显这不是我们想要的结果。通过指定一个空的路径,它就会匹配 /settings
路径,这就是我们想要的结果。
那么 /settings
路由信息,需要在哪里配置?答案是在 AppModule 中。这时我们就需要用到 loadChildren 属性,具体如下:
export const ROUTES: Routes = [ { path: 'settings', loadChildren: () => import('./settings/settings.module').then(it => it.SettingsModule) } ]; @NgModule({ imports: [ BrowserModule, RouterModule.forRoot(ROUTES) ], // ... }) export class AppModule {}
需要注意的是,我们没有将 SettingsModule 导入到我们的 AppModule 中,而是通过 loadChildren 属性,告诉 Angular 路由依据 loadChildren 属性配置的路径去加载 SettingsModule 模块。这就是模块懒加载功能的具体应用,当用户访问 /settings/**
路径的时候,才会加载对应的 SettingsModule 模块,这减少了应用启动时加载资源的大小。
另外我们传递一个字符串作为 loadChildren 的属性值,该字符串由三部分组成:
需要导入模块的相对路径 # 分隔符 导出模块类的名称
了解完路由的一些高级选项和功能,接下来我们来介绍路由指令。
除了 router-outlet
指令,路由模块中还提供了一些其它指令。让我们来看看它们如何与我们之前介绍的内容结合使用。
为了让我们链接到已设置的路由,我们需要使用 routerLink 指令,具体示例如下:
<nav> <a routerLink="/">Home</a> <a routerLink="/settings/password">Change password</a> <a routerLink="/settings/profile">Profile Settings</a> </nav>
当我们点击以上的任意链接时,页面不会被重新加载。反之,我们的路径将在 URL 地址栏中显示,随后进行后续视图更新,以匹配 routerLink 中设置的值。
友情提示:我们也可以将 routerLink 的属性值,改成数组形式,以便我们传递特定的路由信息
如果我们想要链接到动态的路由地址,且该地址有一个 username 的路由变量,则我们可以按照以下方式配置 routerLink 对应的属性值:
<a [routerLink]="['/profile', username]"> Go to {{ username }}'s profile. </a>
在实际开发中,我们需要让用户知道哪个路由处于激活状态,通常情况下我们通过向激活的链接添加一个 class 来实现该功能。为了解决上述问题,Angular 路由模块为我们提供了 routerLinkActive 指令,该指令的使用示例如下:
<nav> <a routerLink="/settings" routerLinkActive="active">Home</a> <a routerLink="/settings/password" routerLinkActive="active">Change password</a> <a routerLink="/settings/profile" routerLinkActive="active">Profile Settings</a> </nav>
通过使用 routerLinkActive 指令,当 a
元素对应的路由处于激活状态时,active
类将会自动添加到 a
元素上。
最后,我们来简单介绍一下 Router API。
我们可以通过路由还提供的 API 实现与 routerLink 相同的功能。要使用 Router API,我们需要在组件类中注入 Router 对象,具体如下:
import { Component } from '@angular/core'; import { Router } from '@angular/router'; @Component({ selector: 'app-root', template: ` <div class="app"> <h3>Our app</h3> <router-outlet></router-outlet> </div> ` }) export class AppComponent { constructor(private router: Router) {} }
组件类中注入的 router 对象中有一个 navigate()
方法,该方法支持的参数类型与 routerLink 指令一样,当调用该方法后,页面将会自动跳转到对应的路由地址。具体使用示例如下:
import { Component, OnInit } from '@angular/core'; import { Router } from '@angular/router'; @Component({ selector: 'app-root', template: ` <div class="app"> <h3>Our app</h3> <router-outlet></router-outlet> </div> ` }) export class AppComponent implements OnInit { constructor(private router: Router) {} ngOnInit() { setTimeout(() => { this.router.navigate(['/settings']); }, 5000); } }
若以上代码成功运行,用户界面将在 5 秒后被重定向到 /settings
页面。这个方法非常有用,例如当检测到用户尚未登录时,自动重定向到登录页面。
另一个使用示例是演示页面跳转时如何传递数据,具体如下:
import { Component, OnInit } from '@angular/core'; import { Router } from '@angular/router'; @Component({ selector: 'app-root', template: ` <div class="app"> <h3>Users</h3> <div *ngFor="let user of users"> <user-component [user]="user" (select)="handleSelect($event)"> </user-component> </div> <router-outlet></router-outlet> </div> ` }) export class AppComponent implements OnInit { users: Username[] = [ { name: 'toddmotto', id: 0 }, { name: 'travisbarker', id: 1 }, { name: 'tomdelonge', id: 2 } ]; constructor(private router: Router) {} handleSelect(event) { this.router.navigate(['/profile', event.name]); } }
Angular 路由的功能非常强大,既可以使用指令方式也可以使用命令式 API,希望本文可以帮助你尽快入门,若要进一步了解路由详细信息,请访问 - Angular Router 官文文档。
路由传参示例/router/823712312938123;h=h;c=c?code=code
<a [routerLink]="['/router', '823712312938123', {h:'h',c:'c'}]" [queryParams]="{code:'code'}">RouterLink 跳转</a> <a (click)="goToDetail()">Navigate 跳转</a>
this.router.navigate([`router/823712312938123`, {h: 'h', c: 'c'}], {queryParams: {code: 'code'}})
在component中取数据
router-demo.component.ts
import {Component, OnInit} from '@angular/core' import {ActivatedRoute} from '@angular/router' @Component({ selector: 'app-router-demo', templateUrl: './router-demo.component.html', styleUrls: ['./router-demo.component.less'] }) export class RouterDemoComponent implements OnInit { constructor(private activatedRoute: ActivatedRoute) { } ngOnInit(): void { const {params, queryParams} = this.activatedRoute.snapshot console.log('params', params) console.log('queryParams', queryParams, queryParams) } }
Angular Router API 提供了 navigate()
和 navigateByUrl()
两个方法来实现页面导航。两者区别如下:
router.navigateByUrl()
方法与直接改变地址栏上的 URL 地址一样,我们使用了一个新的 URL 地址。router.navigate()
方法基于一系列输入参数,产生一个新的 URL 地址。为了更好理解两者区别,有例子,假设当前的 URL 地址是:
/inbox/11/message/22(popup:compose)
当调用 router.navigateByUrl('/inbox/33/message/44')
方法后,当前的 URL 地址将变成/inbox/33/message/44
。
但若是调用 router.navigate('/inbox/33/message/44')
方法,当前的 URL 地址将变成 /inbox/33/message/44(popup:compose)
。
更多编程相关知识,请访问:编程入门!!
以上是淺談Angular中navigate()和navigateByUrl()使用方法的區別的詳細內容。更多資訊請關注PHP中文網其他相關文章!