查看最新的 Angular 6.x 基礎(chǔ)教程
$ npm install -g @angular/cli
$ ng --version
$ ng new angular4-fundamentals
$ ng serve
若想進(jìn)一步了解 Angular CLI 的詳細(xì)信息,請參考 Angular CLI 終極指南。
$ ng generate component simple-form --inline-template --inline-style
## Or
$ ng g c simple-form -it -is # 表示新建組件,該組件使用內(nèi)聯(lián)模板和內(nèi)聯(lián)樣式
在命令行窗口運(yùn)行以上命令后,將輸出以下內(nèi)容:
installing component
create src/app/simple-form/simple-form.component.spec.ts
create src/app/simple-form/simple-form.component.ts
update src/app/app.module.ts
即執(zhí)行上述操作后,創(chuàng)建了兩個文件:
除此之外,update src/app/app.module.ts
表示執(zhí)行上述操作后,Angular CLI 會自動幫我們更新 app.module.ts
文件。所更新的內(nèi)容是把我們新建的組件添加到 NgModule
的 declarations
數(shù)組中,具體如下:
@NgModule({
declarations: [
AppComponent,
SimpleFormComponent
],
...
})
export class AppModule { }
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<h3>{{title}}</h3>
<div>
<app-simple-form></app-simple-form>
</div>
`
})
export class AppComponent {
title = 'Hello, Angular';
}
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-simple-form',
template: `
<p>
simple-form Works!
</p>
`,
styles: []
})
export class SimpleFormComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
從生成的 SimpleFormComponent
組件中,我們發(fā)現(xiàn)組件的 selector
是 app-simple-form
,而我們是使用以下命令創(chuàng)建該組件:
$ ng g c simple-form -it -is
即 Angular CLI 在創(chuàng)建組件時,自動幫我們添加了前綴。那為什么前綴是 app
呢?答案是在項(xiàng)目根目錄下的 .angular-cli.json
文件中,已經(jīng)默認(rèn)幫我們配置了默認(rèn)的前綴,具體如下:
{
...
"apps": [
{
"root": "src",
"outDir": "dist",
...
"prefix": "app",
...
}
],
}
當(dāng)然你可以根據(jù)實(shí)際需求,自行更改默認(rèn)的前綴配置。
在 Angular 中,我們可以使用 (eventName)
語法,進(jìn)行事件綁定。此外,可以使用 #variableName
的語法,定義模板引用。具體示例如下:
import {Component, OnInit} from '@angular/core';
@Component({
selector: 'app-simple-form',
template: `
<div>
<input #myInput type="text">
<button (click)="onClick(myInput.value)">點(diǎn)擊</button>
</div>
`,
styles: []
})
export class SimpleFormComponent implements OnInit {
onClick(value) {
console.log(value);
}
ngOnInit() {}
}
需要注意的是,若我們改變綁定的表達(dá)式為 (click)="onClick(myInput)"
,當(dāng)我們點(diǎn)擊按鈕時,控制臺輸出的結(jié)果是:
<input type="text">
通過該輸出結(jié)果,我們可以知道 #variableName
語法,我們獲取的對象是對應(yīng) DOM 元素的引用。
在第三節(jié)的示例中,假如我們需要獲取鼠標(biāo)事件,那應(yīng)該怎么辦呢?這時,我們可以引入 $event
變量,具體如下:
import {Component, OnInit} from '@angular/core';
@Component({
selector: 'app-simple-form',
template: `
<div>
<input #myInput type="text">
<button (click)="onClick($event, myInput.value)">點(diǎn)擊</button>
</div>
`,
styles: []
})
export class SimpleFormComponent implements OnInit {
onClick(event, value) {
console.log(event);
console.log(value);
}
ngOnInit() {}
}
成功運(yùn)行以上代碼,當(dāng)我們點(diǎn)擊按鈕時,控制臺將輸出:
MouseEvent {isTrusted: true, screenX: 180, screenY: 207, clientX: 165,
clientY: 75…}
需要注意的是,參數(shù)名一定要使用 $event
,否則無法獲取正確的鼠標(biāo)事件。此外,onClick($event, myInput.value)
表達(dá)式中,$event
的順序是任意的,如:
<button (click)="onClick(myInput.value, $event)">點(diǎn)擊</button>
當(dāng) Angular 在調(diào)用我們的事件處理函數(shù)時,會自動幫我們處理調(diào)用的參數(shù)。$event
自動映射為觸發(fā)的事件,與我們 Provider
中 Token
的作用類似。除了監(jiān)聽鼠標(biāo)事件外,我們還可以監(jiān)聽鍵盤事件。
import {Component, OnInit} from '@angular/core';
@Component({
selector: 'app-simple-form',
template: `
<div>
<input #myInput type="text" (keydown.enter)="onEnter($event, myInput.value)">
<button (click)="onClick($event, myInput.value)">點(diǎn)擊</button>
</div>
`,
styles: []
})
export class SimpleFormComponent implements OnInit {
// ...
onEnter(event, value) {
console.log(event);
console.log(value);
}
}
以上代碼中, (keydown.enter)="onEnter($event, myInput.value)"
表達(dá)式表示我們監(jiān)聽鍵盤 enter
鍵的按下事件,當(dāng)我們按下鍵盤的 enter
鍵時,將會調(diào)用組件類中定義的 onEnter()
方法。我們同樣也可以通過 $event
來獲取 KeyboardEvent
對象。
$ ng g s mail
在命令行窗口運(yùn)行以上命令后,將輸出以下內(nèi)容:
installing service
create src/app/mail.service.spec.ts
create src/app/mail.service.ts
WARNING Service is generated but not provided, it must be provided to be used
即執(zhí)行上述操作后,創(chuàng)建了兩個文件:
除此之外,WARNING Service is generated but not provided,...
表示執(zhí)行上述操作后,Angular CLI 只會幫我們創(chuàng)建 MailService
服務(wù),不會自動幫我們配置該服務(wù)。
import {MailService} from "./mail.service";
@NgModule({
...
providers: [MailService],
bootstrap: [AppComponent]
})
export class AppModule { }
import { Injectable } from '@angular/core';
@Injectable()
export class MailService {
message: string ='該消息來自MailService';
constructor() { }
}
import { Component } from '@angular/core';
import {MailService} from "./mail.service";
@Component({
selector: 'app-root',
template: `
<h3>{{title}}</h3>
<div>
<app-simple-form></app-simple-form>
{{mailService.message}}
</div>
`
})
export class AppComponent {
title = 'Hello, Angular';
constructor(private mailService: MailService) {}
}
除了使用 constructor(private mailService: MailService)
方式注入服務(wù)外,我們也可以使用 Inject
裝飾器來注入 MailService
服務(wù):
import {Component, Inject} from '@angular/core';
@Component({...})
export class AppComponent {
title = 'Hello, Angular';
constructor(@Inject(MailService) private mailService) {}
}
不過對于 Type
類型(函數(shù)類型) 的對象,我們一般使用 constructor(private mailService: MailService)
方式進(jìn)行注入。而 Inject
裝飾器一般用來注入非 Type
類型的對象。
@NgModule({
...
providers: [
MailService,
{provide: 'apiUrl', useValue: 'https://jsonplaceholder.typicode.com/'}
],
bootstrap: [AppComponent]
})
export class AppModule { }
@Component({
selector: 'app-root',
template: `
<h3>{{title}}</h3>
<div>
<app-simple-form></app-simple-form>
{{mailService.message}}
<p>API_URL: {{apiUrl}}</p>
</div>
`
})
export class AppComponent {
title = 'Hello, Angular';
constructor(
@Inject(MailService) private mailService,
@Inject('apiUrl') private apiUrl
) {}
}
在 Angular 中我們可以使用 ngFor
指令來顯示數(shù)組中每一項(xiàng)的信息。
import { Injectable } from '@angular/core';
@Injectable()
export class MailService {
messages: string[] = [
'天之驕子,加入修仙之路群',
'Shadows,加入修仙之路群',
'Keriy,加入修仙之路群'
];
}
import {Component} from '@angular/core';
import {MailService} from "./mail.service";
@Component({
selector: 'app-root',
template: `
<h3>{{title}}</h3>
<ul>
<li *ngFor="let message of mailService.messages; index as i;">
{{i}} - {{message}}
</li>
</ul>
`
})
export class AppComponent {
title = 'Hello, Angular';
constructor(private mailService: MailService) {}
}
在 AppComponent 組件的模板中,我們使用 let item of items;
語法迭代數(shù)組中的每一項(xiàng),另外我們使用 index as i
用來訪問數(shù)組中每一項(xiàng)的索引值。除了 index
外,我們還可以獲取以下的值:
需要注意的是,*ngFor
中的 *
號是語法糖,表示結(jié)構(gòu)指令。因?yàn)樵撜Z法最終會轉(zhuǎn)換成:
<ng-template ngFor let-item [ngForOf]="items" let-i="index">
<li>...</li>
</ng-template>
除了 *ngFor
外,常用的結(jié)構(gòu)指令還有 *ngIf
、*ngSwitchCase
指令。
為了讓我們能夠開發(fā)更靈活的組件,Angular 為我們提供了 Input
裝飾器,用于定義組件的輸入屬性。
import {Component, OnInit,Input} from '@angular/core';
@Component({
selector: 'app-simple-form',
template: `
<div>
{{message}}
<input #myInput type="text" (keydown.enter)="onEnter($event, myInput.value)">
<button (click)="onClick($event, myInput.value)">點(diǎn)擊</button>
</div>
`,
styles: []
})
export class SimpleFormComponent implements OnInit {
@Input() message: string;
// ...
}
import {Component} from '@angular/core';
import {MailService} from "./mail.service";
@Component({
selector: 'app-root',
template: `
<h3>{{title}}</h3>
<app-simple-form *ngFor="let message of mailService.messages;"
[message]="message">
</app-simple-form>
`
})
export class AppComponent {
title = 'Hello, Angular';
constructor(private mailService: MailService) {}
}
在 AppComponent 組件模板中,我們使用 [message]="message"
屬性綁定的語法,實(shí)現(xiàn)數(shù)據(jù)傳遞。即把數(shù)據(jù)從 AppComponent
組件,傳遞到 SimpleFormComponent
組件中。
需要注意的是,當(dāng) SimpleFormComponent
組件類的屬性名稱不是 message
時,我們需要告訴 Angular 如何進(jìn)行屬性值綁定,具體如下:
export class SimpleFormComponent implements OnInit {
@Input('message') msg: string;
// ...
}
不過一般不推薦這樣做,盡量保持名稱一致。
使用過 AngularJS 1.x 的同學(xué),應(yīng)該很熟悉 ng-model
指令,通過該指令我們可能方便地實(shí)現(xiàn)數(shù)據(jù)的雙向綁定。而在 Angular 中,我們是通過 ngModel
指令,來實(shí)現(xiàn)雙向綁定。
import {FormsModule} from "@angular/forms";
@NgModule({
// ...
imports: [
BrowserModule,
FormsModule
],
// ...
})
export class AppModule { }
@Component({
selector: 'app-simple-form',
template: `
<div>
{{message}}
<input #myInput type="text" [(ngModel)]="message">
<button (click)="onClick($event, myInput.value)">點(diǎn)擊</button>
</div>
`,
styles: []
})
export class SimpleFormComponent implements OnInit { // ...}
上面示例中,我們使用 [(ngModel)]="message"
語法實(shí)現(xiàn)數(shù)據(jù)的雙向綁定。該語法也稱作 Banana in the Box
語法,即香蕉在盒子里 (比較形象生動,記憶該語法)。
除了使用雙向綁定,我們也可以通過 ngModel
指令,實(shí)現(xiàn)單向數(shù)據(jù)綁定,如 [ngModel]="message"
。
Output
裝飾器的作用是用來實(shí)現(xiàn)子組件將信息,通過事件的形式通知到父級組件。
在介紹 Output 屬性裝飾器前,我們先來介紹一下 EventEmitter
這個幕后英雄:
let numberEmitter: EventEmitter<number> = new EventEmitter<number>();
numberEmitter.subscribe((value: number) => console.log(value));
numberEmitter.emit(10);
接下來我們來介紹如何使用 Output
裝飾器。
import {Component, OnInit, Input, Output, EventEmitter} from '@angular/core';
@Component({
selector: 'app-simple-form',
template: `
<div>
{{message}}
<input #myInput type="text" [(ngModel)]="message">
<button (click)="update.emit({text: message})">更新</button>
</div>
`,
styles: []
})
export class SimpleFormComponent implements OnInit {
@Input() message: string;
@Output() update = new EventEmitter<{text: string}>();
ngOnInit() { }
}
import {Injectable} from '@angular/core';
@Injectable()
export class MailService {
messages: Array<{id: number, text: string}> = [
{id: 0, text: '天之驕子,加入修仙之路群'},
{id: 1, text: 'Shadows,加入修仙之路群'},
{id: 2, text: 'Keriy,加入修仙之路群'}
];
update(id, text) {
this.messages = this.messages.map(msg => {
return msg.id === id ? {id, text} : msg;
});
}
}
import {Component} from '@angular/core';
import {MailService} from "./mail.service";
@Component({
selector: 'app-root',
template: `
<h3>{{title}}</h3>
<ul>
<li *ngFor="let message of mailService.messages;">
{{message.text}}
</li>
</ul>
<app-simple-form *ngFor="let message of mailService.messages;"
[message]="message.text"
(update)="onUpdate(message.id, $event.text)">
</app-simple-form>
`
})
export class AppComponent {
title = 'Hello, Angular';
onUpdate(id, text) {
this.mailService.update(id, text);
}
constructor(private mailService: MailService) {}
}
上面示例中,我們?nèi)匀皇褂?(eventName)
事件綁定的語法,監(jiān)聽我們自定義的 update
事件。當(dāng)在 SimpleFormComponent
組件中修改 input
輸入框的文本消息后,點(diǎn)擊更新按鈕,將會調(diào)用 AppComponent
組件類中的 onUpdate()
方法,更新對應(yīng)的信息。
在 Angular 中,我們可以在設(shè)置組件元數(shù)據(jù)時通過 styles
或 styleUrls
屬性,來設(shè)置組件的內(nèi)聯(lián)樣式和外聯(lián)樣式。
import {Component, OnInit, Input, Output, EventEmitter} from '@angular/core';
@Component({
selector: 'app-simple-form',
template: `
...
`,
styles: [`
:host { margin: 10px; }
input:focus { font-weight: bold;}
`
]
})
export class SimpleFormComponent implements OnInit {
@Input() message: string;
@Output() update = new EventEmitter<{text: string}>();
ngOnInit() {}
}
上面示例中 :host
表示選擇宿主元素,即 AppComponent
組件模板中的 app-simple-form
元素。
用過 AngularJS 1.x 的同學(xué),對 ng-class
應(yīng)該很熟悉,通過它我們能夠根據(jù)條件,為元素動態(tài)的添加或移除對應(yīng)的樣式。在 Angular 中,對應(yīng)的指令是 ngClass
。接下來我們來看一下,ngClass
指令的具體應(yīng)用。
ngClass
指令接收一個對象字面量,對象的 key
是 CSS class 的名稱,value
的值是 truthy/falsy
的值,表示是否應(yīng)用該樣式。
@Component({
selector: 'app-simple-form',
template: `
<div>
{{message}}
<input #myInput
type="text"
[(ngModel)]="message"
[ngClass]="{mousedown: isMousedown}"
(mousedown)="isMousedown = true"
(mouseup)="isMousedown = false"
(mouseleave)="isMousedown = false"
>
<button (click)="update.emit({text: message})">更新</button>
</div>
`,
styles: [`
:host { margin: 10px; }
.mousedown { border: 2px solid green; }
input:focus { font-weight: bold; outline: none;}
`
]
})
export class SimpleFormComponent implements OnInit {
isMousedown: boolean;
// ...
}
<!-- 使用布爾值 -->
<div [ngClass]="{bordered: false}">This is never bordered</div>
<div [ngClass]="{bordered: true}">This is always bordered</div>
<!-- 使用組件實(shí)例的屬性 -->
<div [ngClass]="{bordered: isBordered}">
Using object literal. Border {{ isBordered ? "ON" : "OFF" }}
</div>
<!-- 樣式名包含'-' -->
<div[ngClass]="{'bordered-box': false}">
Class names contains dashes must use single quote
</div>
<!-- 使用樣式列表 -->
<div class="base" [ngClass]="['blue', 'round']">
This will always have a blue background and round corners
</div>
除了 ngClass
指令外,Angular 還為我們提供了 ngStyle
指令。
ngStyle
指令讓我們可以方便得通過 Angular 表達(dá)式,設(shè)置 DOM 元素的 CSS 屬性。
<div [ngStyle]="{color: 'white', 'background-color': 'blue'}">
Uses fixed white text on blue background
</div>
需要注意的是, background-color
需要使用單引號,而 color
不需要。這其中的原因是,ng-style
要求的參數(shù)是一個 Javascript
對象,color
是一個有效的 key
,而 background-color
不是一個有效的 key
,所以需要添加 ''
。
對于一些場合,我們也可以直接利用 Angular 屬性綁定的語法,來快速設(shè)置元素的樣式。
<div [style.background-color="'yellow'"]>
Use fixed yellow background
</div>
<!-- 支持單位: px | em | %-->
<div>
<span [ngStyle]="{color: 'red'}" [style.font-size.px]="fontSize">
Red Text
</span>
</div>
本系列教程的主要目的是讓初學(xué)者對 Angular 的相關(guān)基礎(chǔ)知識,有一定的了解。除了本系列教程外,初學(xué)者還可以參考以下教程:
更多建議: