1. 環(huán)境搭建
0. Before
在開始之前,請確保你的開發(fā)環(huán)境中包括 Node.js? 和 npm 包管理器。
Angular 需要 Node.js 版本 10.9.0 或更高版本。
要檢查你的版本闭树,請?jiān)诮K端/控制臺(tái)窗口中運(yùn)行 node -v 。
1. 安裝 Angular CLI
npm install -g @angular/cli
安裝好之后棉圈,進(jìn)入到你的開發(fā)目錄,使用腳手架創(chuàng)建項(xiàng)目:
ng new my-app
進(jìn)入到項(xiàng)目根目錄,啟動(dòng)項(xiàng)目:
cd my-app
ng serve --open
ng serve 命令會(huì)啟動(dòng)開發(fā)服務(wù)器烈涮、監(jiān)視文件,并在這些文件發(fā)生更改時(shí)重建應(yīng)用窖剑。
2. 項(xiàng)目目錄結(jié)構(gòu)
https://www.angular.cn/guide/file-structure
3. 核心概念
https://www.angular.cn/guide/architecture
- 模塊
- 組件
- 服務(wù)與依賴注入
- 路由
2. Start from TodoList
1. 新建TodoList組件
ng generate component TodoList
2. 創(chuàng)建Todo類
在app下新建Todo.js
export class Todo {
id :number;
name : string;
}
3. 創(chuàng)建todoList數(shù)組
在todo-list.component.ts中導(dǎo)入Todo.js
import {Todo} from '../Todo';
創(chuàng)建todoList數(shù)組:
todoList: Todo[] = [
{id:0,name:"aaaa"},
{id:1,name:"bbbb"},
{id:2,name:"cccc"},
{id:3,name:"dddd"},
{id:4,name:"eeee"}
];
4. 在頁面渲染todolist列表
<ul>
<li *ngFor="let todo of todoList">
<span>{{todo.id}}</span> {{todo.name}}
</li>
</ul>
5. 添加輸入框
在 app.module.ts中導(dǎo)入FormsModule:
import {FormsModule} from '@angular/forms';
并且添加到 imports中:
imports: [
BrowserModule,
FormsModule
],
在todo-list.component.ts中添加:
@Input() text: string;
然后在src/app/todo-list/todo-list.component.html 添加輸入框:
<input type="text" [(ngModel)]="text">
使用 [(ngModel)]="text"
進(jìn)行雙向數(shù)據(jù)綁定坚洽,類似vue中的v-model
這樣就可以實(shí)時(shí)獲取用戶的輸入。
6. 添加按鈕
在頁面上添加按鈕
<button (click)="addTodo()"> 添加 </button>
按鈕綁定了addTodo
事件西土,我們需要實(shí)現(xiàn)這個(gè)方法讶舰,
在src/app/todo-list/todo-list.component.ts中添加:
addTodo(): void {
if(this.text){
this.todoList.push({
id: this.todoList.length,
name: this.text
})
this.text = ''
}
}
這樣當(dāng)用戶輸入后,點(diǎn)擊添加按鈕需了,就會(huì)把用戶數(shù)據(jù)構(gòu)造成Todo對象跳昼,加入到todoList數(shù)組中,這樣頁面上就顯示最新數(shù)據(jù)了援所。
7. 刪除
在每一行todo后添加刪除按鈕
<span>{{todo.id}}</span> {{todo.name}} <span (click)="deleteTodo(todo.id)">delete</span>
刪除按鈕綁定了deleteTodo方法庐舟,同時(shí)把當(dāng)前數(shù)據(jù)id傳入欣除,
deleteTodo的實(shí)現(xiàn):
deleteTodo(id): void {
this.todoList = this.todoList.filter(todo => todo.id != id)
}
3. 路由
在 Angular 中住拭,最好在一個(gè)獨(dú)立的頂級模塊中加載和配置路由器,它專注于路由功能,然后由根模塊 AppModule 導(dǎo)入它滔岳。
1. 生成路由模塊
ng generate module app-routing --flat --module=app
--flat 把這個(gè)文件放進(jìn)了 src/app 中杠娱,而不是單獨(dú)的目錄中。
--module=app 告訴 CLI 把它注冊到 AppModule 的 imports 數(shù)組中谱煤。
通常不會(huì)在路由模塊中聲明組件摊求,所以可以刪除 @NgModule.declarations 并刪除對 CommonModule 的引用。
使用 RouterModule 中的 Routes 類來配置路由器刘离,所以還要從 @angular/router 庫中導(dǎo)入這兩個(gè)符號室叉。
添加一個(gè) @NgModule.exports 數(shù)組,其中放上 RouterModule 硫惕。 導(dǎo)出 RouterModule 讓路由器的相關(guān)指令可以在 AppModule 中的組件中使用茧痕。
此刻的 AppRoutingModule 是這樣的:
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
@NgModule({
exports: [
RouterModule
]
})
export class AppRoutingModule { }
2. 添加路由定義
路由定義 會(huì)告訴路由器,當(dāng)用戶點(diǎn)擊某個(gè)鏈接或者在瀏覽器地址欄中輸入某個(gè) URL 時(shí)恼除,要顯示哪個(gè)視圖踪旷。
典型的 Angular 路由(Route)有兩個(gè)屬性:
path:一個(gè)用于匹配瀏覽器地址欄中 URL 的字符串。
component:當(dāng)導(dǎo)航到此路由時(shí)豁辉,路由器應(yīng)該創(chuàng)建哪個(gè)組件令野。
const route: Routes = [
{path: 'todo', component: TodoListComponent}
];
把 RouterModule 添加到 @NgModule.imports 數(shù)組中
imports: [
RouterModule.forRoot(route),
]
現(xiàn)在完整代碼變成這樣:
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import {TodoListComponent} from './todo-list/todo-list.component';
const route: Routes = [
{path: 'todo', component: TodoListComponent}
];
@NgModule({
imports: [
RouterModule.forRoot(route),
],
exports: [RouterModule],
})
export class AppRoutingModule { }
3. 添加路由出口 (RouterOutlet)
打開 AppComponent 的模板,把里面代碼清空徽级,替換為 <router-outlet> 元素气破。
<router-outlet></router-outlet>
這個(gè)就相當(dāng)于vue中的 <router-view></router-view>
4. 添加用戶頁面
1. 新建一個(gè)用戶組件
ng generate component User
2. 修改路由,添加user路由:
const route: Routes = [
{path: 'todo', component: TodoListComponent},
{path: 'user', component: UserComponent},
];
3. 在src/app/app.component.html上添加導(dǎo)航:
<a routerLink="/todo">todo</a>
<a routerLink="/user">user</a>
這樣當(dāng)用戶點(diǎn)擊導(dǎo)航鏈接時(shí)餐抢,就可以切換頁面堵幽。
4. 設(shè)置默認(rèn)導(dǎo)航,添加:
在 a標(biāo)簽上添加 [routerLinkActive]="'active'"
,并且添加 .active
類
.active
color: #369
border-bottom: solid 2px #369;
<nav>
<a routerLink="/todo" [routerLinkActive]="'active'">todo</a>
<a routerLink="/user" [routerLinkActive]="'active'">user</a>
</nav>
5. 添加User類
在app下新建 User.ts
export class User {
id: number;
name: string;
gender: boolean;
addr: string;
}
修改 src/app/user/user.component.ts,添加users弹澎,代碼如下:
import { Component, OnInit } from '@angular/core';
import {User} from '../User';
@Component({
selector: 'app-user',
templateUrl: './user.component.html',
styleUrls: ['./user.component.styl']
})
export class UserComponent implements OnInit {
users: User[] = [
{id: 0, name: '鋼鐵俠', gender: true, addr: '湖南長沙'},
{id: 1, name: '雪諾', gender: true, addr: '北境'},
{id: 2, name: '黑寡婦', gender: false, addr: '重啟'},
{id: 3, name: '孫悟空', gender: true, addr: '花果山'},
{id: 4, name: '潘金蓮', gender: false, addr: '四川成都'},
];
constructor() { }
ngOnInit() {
}
}
在 src/app/user/user.component.html 中渲染用戶列表:
<div>
<h3>User List</h3>
<ul>
<li *ngFor="let u of users">
{{u.name}} {{u.gender}} {{u.addr}}
</li>
</ul>
</div>
5. Service
1. 什么是服務(wù)
組件不應(yīng)該直接獲取或保存數(shù)據(jù)朴下,它們不應(yīng)該了解是否在展示假數(shù)據(jù)。 它們應(yīng)該聚焦于展示數(shù)據(jù)苦蒿,而把數(shù)據(jù)訪問的職責(zé)委托給某個(gè)服務(wù)殴胧。
服務(wù)可以實(shí)現(xiàn)在多個(gè)類之間共享數(shù)據(jù)。
2. 什么是依賴注入
依賴注入(DI)是一種重要的應(yīng)用設(shè)計(jì)模式佩迟。 Angular 有自己的 DI 框架团滥,在設(shè)計(jì)應(yīng)用時(shí)常會(huì)用到它,以提升它們的開發(fā)效率和模塊化程度报强。
依賴灸姊,是當(dāng)類需要執(zhí)行其功能時(shí),所需要的服務(wù)或?qū)ο蟆?DI 是一種編碼模式秉溉,其中的類會(huì)從外部源中請求獲取依賴力惯,而不是自己創(chuàng)建它們碗誉。
3. 創(chuàng)建可注入的服務(wù)
ng generate service user
這個(gè)令會(huì)在 src/app/user.service.ts 中生成 UserService 類的骨架。 UserService 類的代碼如下:
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class UserService {
constructor() { }
}
4. @Injectable() 服務(wù)
注意父晶,這個(gè)新的服務(wù)導(dǎo)入了 Angular 的 Injectable 符號哮缺,并且給這個(gè)服務(wù)類添加了 @Injectable() 裝飾器。 它把這個(gè)類標(biāo)記為依賴注入系統(tǒng)的參與者之一甲喝。UserService 類將會(huì)提供一個(gè)可注入的服務(wù)尝苇,并且它還可以擁有自己的待注入的依賴。
5. 創(chuàng)建模擬數(shù)據(jù)
在app下新建mock-users.ts,代碼如下:
import {User} from './user';
export const USERS: User[] = [
{id: 0, name: '鋼鐵俠', gender: true, addr: '湖南長沙'},
{id: 1, name: '雪諾', gender: true, addr: '北境'},
{id: 2, name: '黑寡婦', gender: false, addr: '重啟'},
{id: 3, name: '孫悟空', gender: true, addr: '花果山'},
{id: 4, name: '潘金蓮', gender: false, addr: '四川成都'},
];
6. service的實(shí)現(xiàn)
修改src/app/user.service.ts代碼埠胖,添加getUsers方法糠溜,用來獲取用戶,代碼如下:
import { Injectable } from '@angular/core';
import {User} from './User';
import {USERS} from './mock-users';
@Injectable({
providedIn: 'root'
})
export class UserService {
constructor() { }
getUsers(): User[] {
return USERS;
}
}
7. 注入service
在src/app/user/user.component.ts
中導(dǎo)入UserService
:
import {UserService} from '../user.service';
往構(gòu)造函數(shù)中添加一個(gè)私有的 userService直撤,其類型為 UserService诵冒。
constructor(private userService: UserService) { }
這個(gè)參數(shù)同時(shí)做了兩件事:
- 聲明了一個(gè)私有 userService 屬性,
- 把它標(biāo)記為一個(gè) UserService 的注入點(diǎn)谊惭。
當(dāng) Angular 創(chuàng)建 UserComponent 時(shí)汽馋,依賴注入系統(tǒng)就會(huì)把這個(gè) userService 參數(shù)設(shè)置為 UserService 的單例對象。
創(chuàng)建一個(gè)函數(shù)圈盔,以從服務(wù)中獲取這些用戶數(shù)據(jù)豹芯,并在ngOnInit中調(diào)用:
ngOnInit() {
this.getUsers();
}
getUsers(): void {
this.users = this.userService.getUsers();
}
完整代碼如下:
import { Component, OnInit } from '@angular/core';
import {User} from '../User';
import {UserService} from '../user.service';
@Component({
selector: 'app-user',
templateUrl: './user.component.html',
styleUrls: ['./user.component.styl']
})
export class UserComponent implements OnInit {
users: User[] = [];
constructor(private userService: UserService) { }
ngOnInit() {
this.getUsers();
}
getUsers(): void {
this.users = this.userService.getUsers();
}
}
6. http
啟用 HTTP 服務(wù)
HttpClient 是 Angular 通過 HTTP 與遠(yuǎn)程服務(wù)器通訊的機(jī)制。
要讓 HttpClient 在應(yīng)用中隨處可用驱敲,
- 打開根模塊 AppModule铁蹈,
- 從 @angular/common/http 中導(dǎo)入 HttpClientModule 符號,
- 把它加入 @NgModule.imports 數(shù)組众眨。
import { HttpClientModule } from '@angular/common/http';
Http請求
修改src/app/user.service.ts
,代碼如下:
import { Injectable } from '@angular/core';
import {User} from './User';
import {Observable, of} from 'rxjs';
import {HttpClient} from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class UserService {
userUrl = 'https://www.fastmock.site/mock/37666f9c160ab4b9182191952fa5b988/cs/users';
constructor(private http: HttpClient) { }
getUsers(): Observable<User[]> {
return this.http.get<User[]>(this.userUrl);
}
}
在構(gòu)造函數(shù)中添加 http:
constructor(private http: HttpClient) { }
之后使用http
請求數(shù)據(jù):
this.http.get<User[]>(this.userUrl);
由于數(shù)據(jù)請求是異步的握牧,所以使用Observable
把getUsers
方法的返回值改為一個(gè)可觀察對象
調(diào)用服務(wù)
在src/app/user/user.component.ts
中調(diào)用服務(wù),獲取數(shù)據(jù)的結(jié)果現(xiàn)在是一個(gè)Observable
對象娩梨,調(diào)用它的subscribe
方法沿腰,當(dāng)數(shù)據(jù)請求成功后,在其回調(diào)中獲取數(shù)據(jù)狈定,代碼如下:
getUsers(): void {
this.userService.getUsers()
.subscribe( res => {
this.users = res.users;
});
}
7. 詳情頁
1. 創(chuàng)建詳情頁
在用戶列表點(diǎn)擊用戶颂龙,跳轉(zhuǎn)到用戶詳情頁。
首先創(chuàng)建詳情頁:
ng generate component UserDetail
2. 配置路由:
在 src/app/app-routing.module.ts
中導(dǎo)入詳情組件:
import {UserDetailComponent} from './user-detail/user-detail.component';
添加路由配置:
{path: 'detail', component: UserDetailComponent}
在瀏覽器地址欄訪問:http://localhost:4200/detail
,查看詳情頁面纽什。
3. 在用戶類表添加導(dǎo)航鏈接:
<li *ngFor="let u of users">
<a routerLink="/detail/{{u.id}}">
{{u.name}} {{u.gender}} {{u.addr}}
</a>
</li>
同時(shí)修改路由配置;
{path: 'detail/:id', component: UserDetailComponent}
這樣就可以把參數(shù) id
傳遞到詳情組件措嵌,在詳情組件內(nèi)獲取參數(shù);
const id = this.route.snapshot.paramMap.get('id');
4. 調(diào)用service,獲取用戶詳情
添加獲取用戶的方法芦缰,調(diào)用service企巢,傳入用戶id,獲取單個(gè)用戶:
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { UserService} from '../user.service';
import { User } from '../User';
@Component({
selector: 'app-user-detail',
templateUrl: './user-detail.component.html',
styleUrls: ['./user-detail.component.styl']
})
export class UserDetailComponent implements OnInit {
user: User;
constructor(
private route: ActivatedRoute,
private userService: UserService
) { }
ngOnInit() {
this.getHero();
}
getHero(): void {
const id = this.route.snapshot.paramMap.get('id');
this.userService.getUsers()
.subscribe( res => {
this.user = res.users.find(user => user.id + '' === id);
});
}
}
5. 展示詳情信息
獲取到用戶信息后让蕾,展示在詳情頁面:
<div>
<h3>用戶詳情</h3>
<div *ngIf="user">
<p>
{{user.name}}
</p>
<p>
{{user.gender}}
</p>
<p>
{{user.addr}}
</p>
</div>
</div>
6. 返回按鈕
在詳情頁浪规,可以添加一個(gè)返回按鈕或听,點(diǎn)擊返回到上一頁:
8. 管道(過濾器)
管道類似于vue中的過濾器
Angular內(nèi)置的管道有:
- DatePipe
- UpperCasePipe
- LowerCasePipe
- CurrencyPipe
- PercentPipe
使用實(shí)例:
<p>The hero's birthday is {{ birthday | date:"MM/dd/yy" }} </p>
串聯(lián)使用:
{{ birthday | date | uppercase}}
自定義管道
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({name: 'gender'})
export class GenderPipe implements PipeTransform {
transform(value: boolean): string {
return value ? '男' : '女';
}
}
在這個(gè)管道的定義中體現(xiàn)了幾個(gè)關(guān)鍵點(diǎn):
- 管道是一個(gè)帶有“管道元數(shù)據(jù)(pipe metadata)”裝飾器的類。
- 這個(gè)管道類實(shí)現(xiàn)了 PipeTransform 接口的 transform 方法罗丰,該方法接受一個(gè)輸入值和一些可選參數(shù)神帅,并返回轉(zhuǎn)換后的值再姑。
*可以通過 @Pipe 裝飾器來告訴 Angular:這是一個(gè)管道萌抵。該裝飾器是從 Angular 的 core 庫中引入的。 - 這個(gè) @Pipe 裝飾器允許你定義管道的名字元镀,這個(gè)名字會(huì)被用在模板表達(dá)式中绍填。它必須是一個(gè)有效的 JavaScript 標(biāo)識符。 比如栖疑,你這個(gè)管道的名字是 gender讨永。
注意:
在使用之前必須把這個(gè)管道添加到 AppModule 的 declarations 數(shù)組中。
在用戶組件中使用: