Angular快速學習筆記(2) -- 架構


0. angular 與angular js

angular 1.0 google改名為Angular js
新版本的,2.0以上的,繼續叫angular,但是除了名字還叫angular,已經是一個全新的開發框架了。

Angular 是一個用 HTML 和 TypeScript 構建客戶端應用的平台與框架。 Angular 本身使用 TypeScript 寫成的。它將核心功能和可選功能作為一組 TypeScript 庫進行實現,你可以把它們導入你的應用中。

全新的Angular 是一個用 HTML 和 TypeScript 構建客戶端應用的平台與框架。 Angular 本身使用 TypeScript 寫成的。它將核心功能和可選功能作為一組 TypeScript 庫進行實現,你可以把它們導入你的應用中。

1. 架構

Angular 的基本構造塊是 NgModule,它為組件提供了編譯的上下文環境。Angular 應用就是由一組 NgModule 定義出的,應用至少會有一個用於引導應用的根模塊,通常還會有很多特性模塊。
- 組件定義視圖,是可視化部分,每個應用都至少有一個根組件
- 組件使用服務,組件提果數據可視化,而服務提供與視圖不直接相關的功能,后台開發的容易理解。使用服務的好處是服務可以作為依賴被注入到組件中,實現復用,同時還能方便不同模塊做通信。

組件和服務都是簡單的類,這些類使用裝飾器來標出它們的類型。Angular充分利用了裝飾器(java里的annotation)來標識類的類型,並在裝飾器中提供元數據(metadata)來告知ng如何使用它們。

1.1 模塊

Angular 定義了 NgModule,它和 JavaScript(ES2015) 的模塊不同而且有一定的互補性。 NgModule 為一個組件集聲明了編譯的上下文環境,它專注於某個應用領域、某個工作流或一組緊密相關的能力。 NgModule 可以將其組件和一組相關代碼(如服務)關聯起來,形成功能單元。

每個 Angular 應用都有一個根模塊(root module),通常命名為 AppModule。根模塊提供了用來啟動應用的引導機制。 一個應用通常會包含很多功能模塊。

像 JavaScript 模塊一樣,NgModule 也可以從其它 NgModule 中導入功能,並允許導出它們自己的功能供其它 NgModule 使用。 比如,要在你的應用中使用路由器(Router)服務,就要導入 Router 這個 NgModule。

1.1.1 定義一個模塊

一個NgModule就是一個使用@NgModule 裝飾器的類。

@NgModule 裝飾器是一個函數,它接受一個元數據對象,該對象的屬性用來描述這個模塊。其中最重要的屬性如下。

  • declarations(可聲明對象表) —— 那些屬於本 NgModule 的組件、指令、管道
  • exports(導出表) —— 那些能在其它模塊的組件模板中使用的可聲明對象的子集。
  • imports(導入表) —— 那些導出了本模塊中的組件模板所需的類的其它模塊。
  • providers —— 本模塊向全局服務中貢獻的那些服務的創建器。 這些服務能被本應用中的任何部分使用。(你也可以在組件級別指定服務提供商,這通常是首選方式。)
  • bootstrap —— 應用的主視圖,稱為根組件。它是應用中所有其它視圖的宿主。只有根模塊才應該設置這個 bootstrap 屬性。

1.1.2 NgModule 和組件

NgModule 為其中的組件提供了一個編譯上下文環境。根模塊總會有一個根組件,並在引導期間創建它。 但是,任何模塊都能包含任意數量的其它組件,這些組件可以通過路由器加載,也可以通過模板創建。那些屬於這個 NgModule 的組件會共享同一個編譯上下文環境。

enter description here

1.1.3 NgModule 和 JavaScript 的模塊

NgModule 系統與 JavaScript(ES2015)用來管理 JavaScript 對象的模塊系統不同,而且也沒有直接關聯。

JavaScript 中,每個文件是一個模塊,文件中定義的所有對象都從屬於那個模塊。 通過 export 關鍵字,模塊可以把它的某些對象聲明為公共的。 其它 JavaScript 模塊可以使用import 語句來訪問這些公共對象。

NgModule更像一個邏輯上的概念,是一個軟件包的概念。

1.1.4 Angular官方庫

Angular 自帶了一組 JavaScript 模塊,你可以把它們看成庫模塊。每個 Angular 庫的名稱都帶有 @angular 前綴。 使用 npm 包管理器安裝它們,並使用 JavaScript 的 import 語句導入其中的各個部分。

enter description here

例如,從 @angular/core 庫中導入 Component 裝飾器:

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

還可以使用 JavaScript 的導入語句從 Angular 庫中導入 Angular 模塊:

import { BrowserModule } from '@angular/platform-browser'

在上面這個簡單的根模塊范例中,應用的根模塊需要來自 BrowserModule 中的素材。要訪問這些素材,就要把它加入 @NgModule 元數據的 imports 中,代碼如下:

imports:      [ BrowserModule ],

1.2 組件

每個 Angular 應用都至少有一個組件,也就是根組件,它會把組件樹和頁面中的 DOM 連接起來。 每個組件都會定義一個類,其中包含應用的數據和邏輯,並與一個 HTML 模板相關聯,該模板定義了一個供目標環境下顯示的視圖。

enter description here

1.2.1 組件定義

使用@Component 裝飾器來標識一個組件類,並為其指定元數據

@Component({
  selector:    'app-hero-list',
  templateUrl: './hero-list.component.html',
  providers:  [ HeroService ]
})
export class HeroListComponent implements OnInit {
/* . . . */
}
  • selector:是一個 CSS 選擇器,它會告訴 Angular,一旦在模板 HTML 中找到了這個選擇器對應的標簽,就創建並插入該組件的一個實例。 比如,如果應用的 HTML 中包含 <app-hero-list></app-hero-list>,Angular 就會在這些標簽中插入一個 HeroListComponent 實例的視圖。
  • templateUrl:該組件的 HTML 模板文件相對於這個組件文件的地址,實現html與js的分離,推薦
  • 可以用 template 屬性的值來提供內聯的 HTML 模板,類似vuejs和react的單文件。
  • providers 是當前組件所需的依賴注入提供商的一個數組,組件需要用到的service,需要在這里提供

1.2.2 模板與視圖

模板就是一種 HTML,它會告訴 Angular 如何渲染該組件。
視圖通常會分層次進行組織,讓你能以 UI 分區或頁面為單位進行修改、顯示或隱藏。
與組件直接關聯的模板會定義該組件的宿主視圖。該組件還可以定義一個帶層次結構的視圖,它包含一些內嵌的視圖作為其它組件的宿主。

enter description here

1.2.3 模板語法

模板會把 HTML 和 Angular 的標記(markup)組合起來,這些標記可以在 HTML 元素顯示出來之前修改它們。 模板中的指令會提供程序邏輯,而綁定標記會把你應用中的數據和 DOM 連接在一起。

<h2>Hero List</h2>

<p><i>Pick a hero from the list</i></p>
<ul>
  <li *ngFor="let hero of heroes" (click)="selectHero(hero)">
    {{hero.name}}
  </li>
</ul>

<app-hero-detail *ngIf="selectedHero" [hero]="selectedHero"></app-hero-detail>
  • *ngFor 指令告訴 Angular 在一個列表上進行迭代
  • {{hero.name}}(click)[hero] 把程序數據綁定到及綁定回 DOM,以響應用戶的輸入。更多內容參見稍后的數據綁定部分
  • 模板中的 <app-hero-detail> 標簽是一個代表新組件 HeroDetailComponent 的元素

1.2.3.1 數據綁定

Angular的數據綁定標記的四種形式。每種形式都有一個方向 —— 從組件到 DOM、從 DOM 到組件或雙向

enter description here

例如:

<li>{{hero.name}}</li>
<app-hero-detail [hero]="selectedHero"></app-hero-detail>
<li (click)="selectHero(hero)"></li>
  • {{hero.name}}插值表達式在 <li> 標簽中顯示組件的 hero.name 屬性的值。
  • [hero]屬性綁定把父組件 HeroListComponent 的 selectedHero 的值傳到子組件 HeroDetailComponent 的 hero 屬性中。
  • 當用戶點擊某個英雄的名字時,(click) 事件綁定會調用組件的 selectHero 方法。

再來看雙向數據綁定,這個是脫離jq手動綁定數據的偉大發明。

<input [(ngModel)]="hero.name">

在雙向綁定中,數據屬性值通過屬性綁定從組件流到輸入框。用戶的修改通過事件綁定流回組件,把屬性值設置為最新的值。Angular 在每個 JavaScript 事件循環中處理所有的數據綁定,它會從組件樹的根部開始,遞歸處理全部子組件。

enter description here

數據綁定在模板及其組件之間的通訊中扮演了非常重要的角色,它對於父組件和子組件之間的通訊也同樣重要。

enter description here

父組件,通過屬性綁定向子組件傳遞數據,而子組件通過事件綁定向與父組件通信。

1.2.3.2 Pipes管道

一般的模板引擎都會提供pipes功能,angular也不例外,Angular 的管道可以讓你在模板中聲明顯示值的轉換邏輯。 帶有 @Pipe 裝飾器的類中會定義一個轉換函數,用來把輸入值轉換成供視圖顯示用的輸出值。

Angular 自帶了很多管道,比如 date 管道和 currency 管道,完整的列表參見 Pipes API 列表。你也可以自己定義一些新管道。

使用管道:

{{interpolated_value | pipe_name}}

在需要處理的值后面,加上|, 管道還能接收一些參數,來控制它該如何進行轉換。比如,你可以把要使用的日期格式傳給 date 管道:

<!-- Default format: output 'Jun 15, 2015'-->

 <p>Today is {{today | date}}</p>

<!-- fullDate format: output 'Monday, June 15, 2015'-->

<p>The date is {{today | date:'fullDate'}}</p>

 <!-- shortTime format: output '9:43 AM'-->

 <p>The time is {{today | date:'shortTime'}}</p>

1.2.3.2 指令

Angular 的模板是動態的。當 Angular 渲染它們的時候,會根據指令給出的指示對 DOM 進行轉換。 指令就是一個帶有 @Directive 裝飾器的類。

組件其實也是一個指令,但是組件非常獨特、非常重要,因此 Angular 專門定義了 @Component 裝飾器,它使用一些面向模板的特性擴展了 @Directive 裝飾器。

組件就是特殊的指令

除了組件,還有兩種指令:結構型指令屬性型指令。和組件一樣,指令的元數據把指令類和一個 selector 關聯起來,selector 用來把該指令插入到 HTML 中。

在模板中,指令通常作為屬性出現在元素標簽上,可能僅僅作為名字出現,也可能作為賦值目標或綁定目標出現。

結構型指令
結構型指令通過添加、移除或替換 DOM 元素來修改布局

<li *ngFor="let hero of heroes"></li>
<app-hero-detail *ngIf="selectedHero"></app-hero-detail>

屬性型指令
屬性型指令會修改現有元素的外觀或行為。 在模板中,它們看起來就像普通的 HTML 屬性一樣,因此得名“屬性型指令”。

<input [(ngModel)]="hero.name">

Angular 還有很多預定義指令,它們或者修改布局結構(比如 ngSwitch),或者修改 DOM 元素和組件的某些方面(比如 ngStyle 和 ngClass)。

1.3 服務與依賴注入(DI)

對於與特定視圖無關並希望跨組件共享的數據或邏輯,可以創建服務類。 服務類的定義通常緊跟在 “@Injectable” 裝飾器之后。該裝飾器提供的元數據可以讓你的服務作為依賴被注入到客戶組件中。

服務是一個廣義的概念,它包括應用所需的任何值、函數或特性。狹義的服務是一個明確定義了用途的類。它應該做一些具體的事,並做好。

Angular 把組件和服務區分開,以提高模塊性和復用性,這比較契合后端的開發思想,一個類只需要把自己負責的事情做好即可,專業的事情交給專業的類去處理

  • 通過把組件中和視圖有關的功能與其他類型的處理分離開,你可以讓組件類更加精簡、高效
  • 組件不應該定義任何諸如從服務器獲取數據、驗證用戶輸入或直接往控制台中寫日志等工作。 而要把這些任務委托給各種服務。

定義一個服務:

# src/app/logger.service.ts (class)
export class Logger {
  log(msg: any)   { console.log(msg); }
  error(msg: any) { console.error(msg); }
  warn(msg: any)  { console.warn(msg); }
}

1.3.1 依賴注入(dependency injection)

組件是服務的消費者,也就是說,你可以把一個服務注入到組件中,讓組件類得以訪問該服務類。

如何使用:

  • 在 Angular 中,要把一個類定義為服務,就要用 @Injectable 裝飾器來提供元數據,以便讓 Angular 可以把它作為依賴注入到組件中
  • 使用 @Injectable 裝飾器來表明一個組件或其它類(比如另一個服務、管道或 NgModule)擁有一個依賴。 依賴並不必然是服務,它也可能是函數或值等等。
  • 通常在構造函數,注入依賴的service: constructor(private service: HeroService) { }

當 Angular 發現某個組件依賴某個服務時,它會首先檢查是否該注入器中已經有了那個服務的任何現有實例。如果所請求的服務尚不存在,注入器就會使用以前注冊的服務提供商來制作一個,並把它加入注入器中,然后把該服務返回給 Angular。

enter description here

對於要用到的任何服務,你必須至少注冊一個提供商。你可以在模塊中或者組件中注冊這些提供商。
- 當你往根模塊中添加服務提供商時,服務的同一個實例會服務於你應用中的所有組件。
- 當你在組件級注冊提供商時,你會為該組件的每一個新實例提供該服務的一個新實例, 要在組件級注冊,就要在 @Component 元數據的 providers 屬性中注冊服務提供商

因此,對於模塊機共用的service,最好再root模塊中provide,這樣方便一個實例實現共享和通信。

1.4 路由(Routing)

Angular 的 Router 模塊提供了一個服務,它可以讓你定義在應用的各個不同狀態和視圖層次結構之間導航時要使用的路徑。 它的工作模型基於人們熟知的瀏覽器導航約定:

  • 在地址欄輸入 URL,瀏覽器就會導航到相應的頁面
  • 在頁面中點擊鏈接,瀏覽器就會導航到一個新頁面
  • 點擊瀏覽器的前進和后退按鈕,瀏覽器就會在你的瀏覽歷史中向前或向后導航

1.5 架構圖

enter description here

延伸閱讀:


作者:Jadepeng
出處:jqpeng的技術記事本--http://www.cnblogs.com/xiaoqi
您的支持是對博主最大的鼓勵,感謝您的認真閱讀。
本文版權歸作者所有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM