RouterModule
/projects/:id
在傳統網頁,每次換頁都會整個重新載入;但在 SPA(Single Page Application)裡,Routing 是前端框架模擬「換頁」,實際上只是切換元件。
Angular Router 提供:
RouterModule.forRoot(routes)
→ 定義路由表<router-outlet>
→ 畫面插槽,顯示目前路由對應的元件[routerLink]
→ 模板中的導覽連結ActivatedRoute
→ 在元件裡讀取當前路由參數編輯 app.module.ts
:
import { RouterModule, Routes } from '@angular/router';
// 定義路由表
const routes: Routes = [
{ path: '', component: ProjectsComponent }, // 預設首頁顯示作品集
{ path: 'projects/:id', component: ProjectDetailComponent }, // 動態路由
{ path: '**', redirectTo: '' } // 兜底:無效網址回首頁
];
@NgModule({
declarations: [
AppComponent,
// ...其他元件
ProjectDetailComponent
],
imports: [
BrowserModule,
RouterModule.forRoot(routes),
FormsModule,
ReactiveFormsModule,
],
bootstrap: [AppComponent],
})
export class AppModule {}
用 CLI 新增:
ng g c components/project-detail
檔案結構:
src/app/components/project-detail/
├─ project-detail.component.ts
├─ project-detail.component.html
└─ project-detail.component.scss
projects.component.html
<section id="projects" class="container section">
<h2>作品集 Projects</h2>
<div class="project-grid">
<article class="card" *ngFor="let project of projects; let i = index; trackBy: trackByTitle">
<h3>{{ project.title }}</h3>
<p class="muted">{{ project.tech }}</p>
<p>{{ project.desc }}</p>
<!-- 使用 routerLink 取代 href -->
<a class="btn small" [routerLink]="['/projects', i]">查看詳情</a>
</article>
</div>
</section>
這裡我們用 i
(index)當作簡單的 id。未來可以換成資料庫 ID。
project-detail.component.ts
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { ProjectsDataService } from '../../services/projects-data.service';
import { Project } from '../../models/project.model';
@Component({
selector: 'app-project-detail',
templateUrl: './project-detail.component.html',
styleUrls: ['./project-detail.component.scss']
})
export class ProjectDetailComponent implements OnInit {
project?: Project;
constructor(
private route: ActivatedRoute,
private projectsSvc: ProjectsDataService
) {}
ngOnInit(): void {
// 從網址讀取參數
const id = Number(this.route.snapshot.paramMap.get('id'));
const all = this.projectsSvc.getAll();
this.project = all[id]; // 簡化處理:直接用 index
}
}
project-detail.component.html
<div class="container section" *ngIf="project">
<h2>{{ project.title }}</h2>
<p class="muted">{{ project.tech }}</p>
<p>{{ project.desc }}</p>
<a class="btn" [href]="project.link" target="_blank">前往 Demo</a>
<br /><br />
<a routerLink="/" class="btn btn-outline">返回首頁</a>
</div>
<router-outlet>
修改 app.component.html
:
<app-header></app-header>
<router-outlet></router-outlet>
<app-footer></app-footer>
/
→ 顯示作品集(多個卡片)/projects/0
或 /projects/1
/
AppModule
匯入 RouterModule
<router-outlet>
→ 會報錯imports: [RouterModule.forRoot(routes)]
<a href="...">
<a href="/projects/0">
→ 會整個 reload<a [routerLink]="['/projects', 0]">
→ SPA 內部切換Number(...)
*
,輸入錯誤網址會白畫面我們要進一步學 Router 的巢狀結構與 Lazy Loading:
/projects/0/info
、/projects/0/gallery
)children
與 <router-outlet>
巢狀使用