基礎(chǔ)教程

2018-08-28 10:25 更新

查看最新的 Angular 6.x 基礎(chǔ)教程

目錄

  • 第一節(jié) - 基于 Angular CLI 新建項(xiàng)目
  • 第二節(jié) - 創(chuàng)建簡單的組件
  • ?第三節(jié) - 事件和模板引用
  • 第四節(jié) - 事件進(jìn)階
  • 第五節(jié) - 注入服務(wù)
  • 第六節(jié) - 使用 ngFor 指令
  • 第七節(jié) - 使用 Input 裝飾器
  • 第八節(jié) - 使用雙向綁定
  • 第九節(jié) - 使用 Output 裝飾器
  • 第十節(jié) - 組件樣式

第一節(jié) - 基于 Angular CLI 新建項(xiàng)目

安裝 Angular CLI (可選)

$ npm install -g @angular/cli

  • 檢測 Angular CLI 是否安裝成功

$ ng --version

使用 Angular CLI

  • 新建項(xiàng)目

$ ng new angular4-fundamentals

  • 啟動本地服務(wù)器

$ ng serve

若想進(jìn)一步了解 Angular CLI 的詳細(xì)信息,請參考 Angular CLI 終極指南

第二節(jié) - 創(chuàng)建簡單的組件

新建組件

$ 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)建了兩個文件:

  • simple-form.component.spec.ts - 用于單元測試
  • simple-form.component.ts - 新建的組件

除此之外,update src/app/app.module.ts 表示執(zhí)行上述操作后,Angular CLI 會自動幫我們更新 app.module.ts 文件。所更新的內(nèi)容是把我們新建的組件添加到 NgModuledeclarations 數(shù)組中,具體如下:

@NgModule({
  declarations: [
    AppComponent,
    SimpleFormComponent
  ],
  ...
})
export class AppModule { }

使用組件

AppComponent

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';
}

SimpleFormComponent

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)組件的 selectorapp-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)的前綴配置。

第三節(jié) - 事件和模板引用

在 Angular 中,我們可以使用 (eventName) 語法,進(jìn)行事件綁定。此外,可以使用 #variableName 的語法,定義模板引用。具體示例如下:

SimpleFormComponent

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é) - 事件進(jìn)階

獲取鼠標(biāo)事件

在第三節(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ā)的事件,與我們 ProviderToken 的作用類似。除了監(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 對象。

第五節(jié) - 注入服務(wù)

新建服務(wù)

$ 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)建了兩個文件:

  • mail.service.spec.ts - 用于單元測試
  • mail.service.ts - 新建的服務(wù)

除此之外,WARNING Service is generated but not provided,... 表示執(zhí)行上述操作后,Angular CLI 只會幫我們創(chuàng)建 MailService 服務(wù),不會自動幫我們配置該服務(wù)。

配置服務(wù)

import {MailService} from "./mail.service";


@NgModule({
  ...
  providers: [MailService],
  bootstrap: [AppComponent]
})
export class AppModule { }

更新服務(wù)

import { Injectable } from '@angular/core';


@Injectable()
export class MailService {
  message: string  ='該消息來自MailService';
  constructor() { }
}

使用服務(wù)

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 類型的對象。

使用Inject裝飾器

AppModule

@NgModule({
  ...
  providers: [
    MailService,
    {provide: 'apiUrl', useValue: 'https://jsonplaceholder.typicode.com/'}
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

AppComponent

@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
  ) {}
}

第六節(jié) - 使用 ngFor 指令

在 Angular 中我們可以使用 ngFor 指令來顯示數(shù)組中每一項(xiàng)的信息。

使用 ngFor 指令

更新 MailService 服務(wù)

import { Injectable } from '@angular/core';


@Injectable()
export class MailService {
  messages: string[] = [
    '天之驕子,加入修仙之路群',
    'Shadows,加入修仙之路群',
    'Keriy,加入修仙之路群'
  ];
}

更新 AppComponent 組件

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 外,我們還可以獲取以下的值:

  • first: boolean - 若當(dāng)前項(xiàng)是可迭代對象的第一項(xiàng),則返回 true
  • last: boolean - 若當(dāng)前項(xiàng)是可迭代對象的最后一項(xiàng),則返回 true
  • even: boolean - 若當(dāng)前項(xiàng)的索引值是偶數(shù),則返回 true
  • odd: boolean - 若當(dāng)前項(xiàng)的索引值是奇數(shù),則返回 true

需要注意的是,*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 指令。

第七節(jié) - 使用 Input 裝飾器

為了讓我們能夠開發(fā)更靈活的組件,Angular 為我們提供了 Input 裝飾器,用于定義組件的輸入屬性。

使用 Input 裝飾器

更新 SimpleFormComponent 組件

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;
  // ...
}

更新 AppComponent 組件

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;
  // ...
}

不過一般不推薦這樣做,盡量保持名稱一致。

第八節(jié) - 使用雙向綁定

使用過 AngularJS 1.x 的同學(xué),應(yīng)該很熟悉 ng-model 指令,通過該指令我們可能方便地實(shí)現(xiàn)數(shù)據(jù)的雙向綁定。而在 Angular 中,我們是通過 ngModel 指令,來實(shí)現(xiàn)雙向綁定。

使用雙向綁定

引入 FormsModule

import {FormsModule} from "@angular/forms";


@NgModule({
  // ...
  imports: [
    BrowserModule,
    FormsModule
  ],
  // ...
})
export class AppModule { }

使用 ngModel 指令

@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 語法,即香蕉在盒子里 (比較形象生動,記憶該語法)。

banana-in-box

除了使用雙向綁定,我們也可以通過 ngModel 指令,實(shí)現(xiàn)單向數(shù)據(jù)綁定,如 [ngModel]="message"。

第九節(jié) - 使用 Output 裝飾器

Output 裝飾器的作用是用來實(shí)現(xiàn)子組件將信息,通過事件的形式通知到父級組件。

在介紹 Output 屬性裝飾器前,我們先來介紹一下 EventEmitter 這個幕后英雄:

let numberEmitter: EventEmitter<number> = new EventEmitter<number>(); 
numberEmitter.subscribe((value: number) => console.log(value));
numberEmitter.emit(10);

接下來我們來介紹如何使用 Output 裝飾器。

使用 Output 裝飾器

更新 SimpleFormComponent 組件

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() { }
}

更新 MailService 服務(wù)

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;
    });
  }
}

更新 AppComponent 組件

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)的信息。

第十節(jié) - 組件樣式

在 Angular 中,我們可以在設(shè)置組件元數(shù)據(jù)時通過 stylesstyleUrls 屬性,來設(shè)置組件的內(nèi)聯(lián)樣式和外聯(lián)樣式。

使用 styles 屬性

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 指令

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;
  // ...
}

ngClass 指令用法

<!-- 使用布爾值 -->
<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 指令

ngStyle 指令讓我們可以方便得通過 Angular 表達(dá)式,設(shè)置 DOM 元素的 CSS 屬性。

ngStyle 指令用法

<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è)置元素的樣式。

  • 設(shè)置元素的背景顏色

<div [style.background-color="'yellow'"]>
  Use fixed yellow background
</div> 

  • 設(shè)置元素的字體大小

<!-- 支持單位: px | em | %-->
<div>
   <span [ngStyle]="{color: 'red'}" [style.font-size.px]="fontSize">
      Red Text
   </span>
</div>

我有話說

除了本系列教程外,還有其它入門的資料么?

本系列教程的主要目的是讓初學(xué)者對 Angular 的相關(guān)基礎(chǔ)知識,有一定的了解。除了本系列教程外,初學(xué)者還可以參考以下教程:

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號