Angular 4 基礎教程

本系列教程的主要內容來源於 egghead.io get-started-with-angular 視頻教程,但針對視頻中的介紹的知識點作了適當地補充,建議有興趣的同窗直接查看該視頻教程。
另外建了個羣有興趣的朋友能夠加一下 QQ 羣:Angular 修仙之路 - 153742079 (羣名稱規則:城市 + 暱稱)

目錄

  • 第一節 - 基於 Angular CLI 新建項目
  • 第二節 - 建立簡單的組件
  • ​第三節 - 事件和模板引用
  • 第四節 - 事件進階
  • 第五節 - 注入服務
  • 第六節 - 使用 ngFor 指令
  • 第七節 - 使用 Input 裝飾器
  • 第八節 - 使用雙向綁定
  • 第九節 - 使用 Output 裝飾器
  • 第十節 - 組件樣式
查看新版教程,請訪問 Angular 6.x 基礎教程

第一節 - 基於 Angular CLI 新建項目

安裝 Angular CLI (可選)

$ npm install -g @angular/cli
  • 檢測 Angular CLI 是否安裝成功
$ ng --version

使用 Angular CLI

  • 新建項目
$ ng new angular4-fundamentals
  • 啓動本地服務器
$ ng serve

若想進一步瞭解 Angular CLI 的詳細信息,請參考 Angular CLI 終極指南css

第二節 - 建立簡單的組件

新建組件

$ ng generate component simple-form --inline-template --inline-style
# Or
$ ng g c simple-form -it -is # 表示新建組件,該組件使用內聯模板和內聯樣式

在命令行窗口運行以上命令後,將輸出如下內容:html

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

即執行上述操做後,建立了兩個文件:node

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

除此以外,update src/app/app.module.ts 表示執行上述操做後,Angular CLI 會自動幫咱們更新 app.module.ts 文件。所更新的內容是把咱們新建的組件添加到 NgModuledeclarations 數組中,具體以下:git

@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 組件中,咱們發現組件的 selectorapp-simple-form,而咱們是使用如下命令建立該組件:github

$ ng g c simple-form -it -is

即 Angular CLI 在建立組件時,自動幫咱們添加了前綴。那爲何前綴是 app 呢?答案是在項目根目錄下的 .angular-cli.json 文件中,已經默認幫咱們配置了默認的前綴,具體以下:typescript

{
  ...
  "apps": [
    {
      "root": "src",
      "outDir": "dist",
      ...
      "prefix": "app",
       ...
    }
  ],
}

固然你能夠根據實際需求,自行更改默認的前綴配置。shell

第三節 - 事件和模板引用

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

SimpleFormComponent

import {Component, OnInit} from '@angular/core';

@Component({
  selector: 'app-simple-form',
  template: `
    <div>
     <input #myInput type="text">
     <button (click)="onClick(myInput.value)">點擊</button>
    </div>
  `,
  styles: []
})
export class SimpleFormComponent implements OnInit {
  onClick(value) {
    console.log(value);
  }

  ngOnInit() {}
}

須要注意的是,若咱們改變綁定的表達式爲 (click)="onClick(myInput)" ,當咱們點擊按鈕時,控制檯輸出的結果是:json

<input type="text">

經過該輸出結果,咱們能夠知道 #variableName 語法,咱們獲取的對象是對應 DOM 元素的引用。bootstrap

第四節 - 事件進階

獲取鼠標事件

在第三節的示例中,假如咱們須要獲取鼠標事件,那應該怎麼辦呢?這時,咱們能夠引入 $event 變量,具體以下:

import {Component, OnInit} from '@angular/core';

@Component({
  selector: 'app-simple-form',
  template: `
    <div>
     <input #myInput type="text">
     <button (click)="onClick($event, myInput.value)">點擊</button>
    </div>
  `,
  styles: []
})
export class SimpleFormComponent implements OnInit {
  onClick(event, value) {
    console.log(event);
    console.log(value);
  }
  ngOnInit() {}
}

成功運行以上代碼,當咱們點擊按鈕時,控制檯將輸出:

MouseEvent {isTrusted: true, screenX: 180, screenY: 207, clientX: 165,
  clientY: 75…}

須要注意的是,參數名必定要使用 $event ,不然沒法獲取正確的鼠標事件。此外,onClick($event, myInput.value) 表達式中,$event 的順序是任意的,如:

<button (click)="onClick(myInput.value, $event)">點擊</button>

當 Angular 在調用咱們的事件處理函數時,會自動幫咱們處理調用的參數。$event 自動映射爲觸發的事件,與咱們 ProviderToken 的做用相似。除了監聽鼠標事件外,咱們還能夠監聽鍵盤事件。

獲取鍵盤事件

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)">點擊</button>
    </div>
  `,
  styles: []
})
export class SimpleFormComponent implements OnInit {
  // ...
  onEnter(event, value) {
    console.log(event);
    console.log(value);
  }
}

以上代碼中, (keydown.enter)="onEnter($event, myInput.value)" 表達式表示咱們監聽鍵盤 enter 鍵的按下事件,當咱們按下鍵盤的 enter 鍵時,將會調用組件類中定義的 onEnter() 方法。咱們一樣也能夠經過 $event 來獲取 KeyboardEvent 對象。

第五節 - 注入服務

新建服務

$ ng g s mail

在命令行窗口運行以上命令後,將輸出如下內容:

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

即執行上述操做後,建立了兩個文件:

  • mail.service.spec.ts - 用於單元測試
  • mail.service.ts - 新建的服務

除此以外,WARNING Service is generated but not provided,... 表示執行上述操做後,Angular CLI 只會幫咱們建立 MailService 服務,不會自動幫咱們配置該服務。

配置服務

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) 方式注入服務外,咱們也可使用 Inject 裝飾器來注入 MailService 服務:

import {Component, Inject} from '@angular/core';

@Component({...})
export class AppComponent {
  title = 'Hello, Angular';
  
  constructor(@Inject(MailService) private mailService) {}
}

不過對於 Type 類型(函數類型) 的對象,咱們通常使用 constructor(private mailService: MailService) 方式進行注入。而 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
  ) {}
}

第六節 - 使用 ngFor 指令

在 Angular 中咱們可使用 ngFor 指令來顯示數組中每一項的信息。

使用 ngFor 指令

更新 MailService 服務

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; 語法迭代數組中的每一項,另外咱們使用 index as i 用來訪問數組中每一項的索引值。除了 index 外,咱們還能夠獲取如下的值:

  • first: boolean - 若當前項是可迭代對象的第一項,則返回 true
  • last: boolean - 若當前項是可迭代對象的最後一項,則返回 true
  • even: boolean - 若當前項的索引值是偶數,則返回 true
  • odd: boolean - 若當前項的索引值是奇數,則返回 true

須要注意的是,*ngFor 中的 * 號是語法糖,表示結構指令。由於該語法最終會轉換成:

<ng-template ngFor let-item [ngForOf]="items" let-i="index">
  <li>...</li>
</ng-template>

除了 *ngFor 外,經常使用的結構指令還有 *ngIf*ngSwitchCase 指令。

第七節 - 使用 Input 裝飾器

爲了讓咱們可以開發更靈活的組件,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)">點擊</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" 屬性綁定的語法,實現數據傳遞。即把數據從 AppComponent 組件,傳遞到 SimpleFormComponent 組件中。

須要注意的是,當 SimpleFormComponent 組件類的屬性名稱不是 message 時,咱們須要告訴 Angular 如何進行屬性值綁定,具體以下:

export class SimpleFormComponent implements OnInit {
  @Input('message') msg: string;
  // ...
}

不過通常不推薦這樣作,儘可能保持名稱一致。

第八節 - 使用雙向綁定

使用過 AngularJS 1.x 的同窗,應該很熟悉 ng-model 指令,經過該指令咱們可能方便地實現數據的雙向綁定。而在 Angular 中,咱們是經過 ngModel 指令,來實現雙向綁定。

使用雙向綁定

引入 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)">點擊</button>
    </div>
  `,
  styles: []
})
export class SimpleFormComponent implements OnInit { // ...}

上面示例中,咱們使用 [(ngModel)]="message" 語法實現數據的雙向綁定。該語法也稱做 Banana in the Box 語法,即香蕉在盒子裏 (比較形象生動,記憶該語法)。

banana-in-box

除了使用雙向綁定,咱們也能夠經過 ngModel 指令,實現單向數據綁定,如 [ngModel]="message"

第九節 - 使用 Output 裝飾器

Output 裝飾器的做用是用來實現子組件將信息,經過事件的形式通知到父級組件。

在介紹 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 服務

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

上面示例中,咱們仍然使用 (eventName) 事件綁定的語法,監聽咱們自定義的 update 事件。當在 SimpleFormComponent 組件中修改 input 輸入框的文本消息後,點擊更新按鈕,將會調用 AppComponent 組件類中的 onUpdate() 方法,更新對應的信息。

第十節 - 組件樣式

在 Angular 中,咱們能夠在設置組件元數據時經過 stylesstyleUrls 屬性,來設置組件的內聯樣式和外聯樣式。

使用 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 的同窗,對 ng-class 應該很熟悉,經過它咱們可以根據條件,爲元素動態的添加或移除對應的樣式。在 Angular 中,對應的指令是 ngClass 。接下來咱們來看一下,ngClass 指令的具體應用。

使用 ngClass 指令

ngClass 指令接收一個對象字面量,對象的 key 是 CSS class 的名稱,value 的值是 truthy/falsy 的值,表示是否應用該樣式。

@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>

<!-- 使用組件實例的屬性 -->
<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 表達式,設置 DOM 元素的 CSS 屬性。

ngStyle 指令用法

<div [ngStyle]="{color: 'white', 'background-color': 'blue'}">
   Uses fixed white text on blue background
</div>

須要注意的是, background-color 須要使用單引號,而 color 不須要。這其中的緣由是,ng-style 要求的參數是一個 Javascript 對象,color 是一個有效的 key,而 background-color 不是一個有效的 key ,因此須要添加 ''

對於一些場合,咱們也能夠直接利用 Angular 屬性綁定的語法,來快速設置元素的樣式。

  • 設置元素的背景顏色
<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>

我有話說

應該如何引入第三方 UI 庫,如 bootstrap

若要引入第三方 UI 庫,能夠在 .angular-cli.json 文件中,配置對應的樣式文件地址,具體以下:

{
  "apps": {
     "styles": [
         "styles.css",
         "../node_modules/bootstrap/dist/css/bootstrap.min.css"
      ]
  }
}

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

本系列教程的主要目的是讓初學者對 Angular 的相關基礎知識,有必定的瞭解。除了本系列教程外,初學者還能夠參考如下教程:

相關文章
相關標籤/搜索