angular 應用:用帶 angular 拓展語法的 HTML 寫模板,用組件類管理這些模板,用服務添加應用邏輯,在模塊中打包發佈組件與服務。通過引導 根模塊啟動應用。 angular 在瀏覽器中接管、展現應用的內容,並根據我們提供的操作指令響應用戶的交互。
這幾個名詞很重要,貫穿angular應用開發。
angular 應用的 8個主要構造塊:
模塊modules 組件components 模板template 元數據metadata 數據綁定data binding 指令directive 服務services 依賴註入dependency injection
模塊
angular 應用是模塊化的,有自己的模塊系統,叫做 angular 模塊/NgModules。
到底模塊是什麼?在angular裡模塊化意味著什麼?
angular 應用至少有一個模塊(根模塊),稱為 AppModule。
大多數應用都有很多其它的 特性模塊,它們由一組領域類、工作流、或緊密相關的功能聚合形成。
angular的所有模塊都是一個帶有 @NgModule 裝飾器的類。
angular的模塊是類!!!
裝飾器是用來修飾JavaScript類的函數。負責把元數據附加到類上。
NgModule 是一個裝飾器函數,它接收一個用來描述模塊屬性的元數據對象。屬性有:
declarations(聲明):本模塊中擁有的視圖類。angular 有三種視圖類:組件、指令、管道。 exports:declarations的子集,可用於其它模塊中的組件模板。 imports:本模塊組件模板中需要由其他模板導出的類。 providers:服務的創建者。本模塊把它們加入全局的服務表中,讓他們在應用中的任何部分都可被訪問到。 bootstrap:標識出應用的主視圖(根組件)。隻有根模塊才可設置此屬性。
下面是一個簡單的根模塊:
// app.module.ts import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; // @NgModle 裝飾器函數,接受一個對象,對象有幾個屬性 @NgModule({ imports: [ BrowserModule ], providers: [ Logger ], declarations: [ AppComponent ], exports: [ AppComponent ], bootstrap: [ AppComponent ] }) // AppComponent 的 export 語句導出,根模塊不需要導出,其他組件不需導入根模塊。 export class AppModule { }
引導根模塊來啟動應用。在 main.ts 文件中引導 AppModule:
// app/main.ts import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; // 從app.module 文件導入瞭 AppModule import { AppModule } from './app.module'; platformBrowserDynamic().bootstrapModule(AppModule);
此時,項目隻有 app/app.module.ts 文件和 app/main.ts ,前者定義瞭應用的根模塊,後者引用它來啟動應用。
Angular 模塊與JavaScript模塊比較:
JavaScript的模塊化是分文件導入的,各文件就是各模塊。
Angular 模塊(用 @NgModule 裝飾的類)是Angular的基礎特性。
JavaScript的模塊系統管理一組JavaScript對象。
在JavaScript中,每個文件就是一個模塊,該文件中定義的對象從屬於該模塊。通過 export 關鍵字,可以把它的某些對象聲明為公開。別的模塊可以使用 import 語句訪問公開對象。
JavaScript的這個特性很有用。
export 關鍵字聲明為公開,import 語句訪問公開對象。
在 Angular 裡這兩種都會用到,從上面的兩個個文件裡,可以看到。
模塊庫
上面所說,Angular 用到瞭 JavaScript模塊,所以它的JS模塊就是庫模塊,JS文件庫。
Angular 庫的名字都以 @angular 前綴,可以使用 npm 包管理工具安裝,並如上面的 import 語句可以訪問它們中的對象。
這點很好理解,Angular 本來就是依托於JS實現的單頁面框架,所以它本身還是需要豐富的JS庫的。
比如,從 @angular/core 庫導入 Component 裝飾器:
import { Component } from '@angular/core';
使用JavaScript導入語句從Angular 庫中導入 Angular 的某些模塊。
import { BrowserModule } from '@angular/platform-browser';
在上面根模塊的代碼中,應用模塊需要 BrowserModule 的某些素材,所以把它加入 @NgModule 元數據的 imports 中:
imports :[ BrowserModule ];
我們看看基本的@angular庫中有哪些JS模塊:
common compiler core forms http platform-browser platform-browser-dynamic router upgrade
所以,我們同時使用 Angular 和 JavaScript的模塊化系統。
這塊的 imports 和 exports 比較混亂,可以自己梳理下。
組件
組件負責控制屏幕上的一小塊地方,就是視圖。
在類中定義組件的應用邏輯(被用來為視圖提供支持)。組件通過一些由屬性和方法組成的API與視圖交互。
所以說組件是聯系視圖的。
前面的 export 關鍵字可以把模塊中的類聲明為公開的,然後 import 裡實現訪問。
類裡面有許多屬性和方法。
模板
通過組件自帶的模板來定義視圖。模板是以HTML形式存在的,它告訴 Angular 如何渲染組件(視圖)。
看一個組件文件的模板:
// app/hero-list.component.html
Hero List
Pick a hero from the list
- {{hero.name}}
模板看起來就是標準 HTML,它裡面有一些非標準HTML的語法。*ngFor、{{hero.name}}、{click}、[hero] 和 ,它們是 Angular 的模板語法。
所以說,Angular 是通過這種方式來處理 HTML的。
元數據
元數據告訴Angular如何處理一個類。
之前 export 的類裡有一些方法和屬性,但是怎麼處理這個類?
隻要把元數據附加到這個類,就意味著這個類是個組件。
在 TypeScript 中,我們用裝飾器(decorator)來附加元數據。
分析下面的元數據:
// app/hero-list.component.ts @Component({ moduleId: module.id, selector: 'hero-list', templateUrl: 'hero-list.component.html', providers: [ HeroService ] }) export class HeroListComponent implements OnInit { /* . . . */ }
@Component裝飾器把緊隨其後的類標記成瞭組件類。
在裝飾器後面的類就會被轉為組件類?
裝飾器裡的配置項:
moduleId:為與模塊相關的URL提供基地址。
這個地址怎麼使用的?
selector:CSS 選擇器,它告訴 Angular 在父級HTML尋找一個標簽,然後創建組件實例並插入標簽中。
實現HTML的顯示。
templateUrl:組件HTML模板的模塊相對地址。
HTML模板的設置位置。
providers:數組,包含組件所依賴的服務所需要的依賴註入提供商。告訴Angular該組件的構造函數需要服務,組件可以從服務獲取數據。
某些數據的傳遞通過服務進行,否則,其他的視圖隻能控制靜態的展示。
@Component 裡的元數據會告訴 Angular 如何取得你為組件設定的元數據。
模板、元數據和組件共同描繪出這個視圖。
組件就是視圖,模板提供HTML的結構性。
數據綁定
如果沒有框架,那麼一些都需要我們來做。把數據值推送到HTML控件,並把用戶的反饋接收轉換成動作和值更新顯示,你可以使用jQuery來實現這個過程。
Angular 框架實現數據綁定,一種讓模板各部分與組件的各部分相互聯系的機制。在模板HTML中添加綁定標記,Angular 會連接模板和組件。
意味著,我們刻意自動實現視圖數據的更新,因為它綁定瞭組件,可以實現數據的關聯。
看一個示例:
// app/hero-list.component.ts
- {{hero.name}}
觀察到在這個模板HTML裡,有一些非標準HTML的字符。
{{hero.name}} 插值表達式:在元素中顯示組件的 hero.name屬性的值。
[hero] 屬性綁定:把父組件的值傳到子組件的 hero 屬性中。
(click) 事件綁定:當用戶點擊元素時調用方法。
文件之間的互相關系需要梳理清楚。
雙向數據綁定:同時實現屬性綁定和事件綁定的功能。看示例:
// app/hero-detail.component.ts
數據屬性的值會從具有屬性綁定的組件傳到輸入框,事件綁定使用戶的修改被傳回組件,把屬性值設為最新的值。
指令
Angular 模板是動態的。當 Angular 渲染它們時,它會根據指令對DOM進行修改。
就是說解析模板HTML的時候,會解析其中的指令。
指令是一個帶有指令元數據的類。
指令是一個類,並且它含有指令源數據。
在TypeScript中,要通過 @Directive 裝飾器把元數據附加到類上。
和之前的類的元數據一樣,通過 @Component 裝飾器把元數據附加到後面的類,編程組件類。這個就是通過 @Directive 裝飾器把一些元數據附加到後面的指令類。
結構型指令:通過在DOM中添加、移除、替換元素修改佈局。ngFor 、 ngIf。
屬性指令:修改現有元素的外觀或行為。ngModel
服務
服務分很多種,值、函數、應用所需的特性。
幾乎任何東西都可以是一個服務。典型的服務是一個類。
例如:
日志服務 數據服務 消息總線 稅款計算器 應用程序配置
組件是最大的服務消費者。
組件的一些操作需要服務提供一些數據。
示例,把日志記錄顯示到瀏覽器控制臺:
// app/logger.service.ts export class Logger { log(msg: any) { console.log(msg); } error(msg: any) { console.error(msg); } warn(msg: any) { console.warn(msg); } }
這些服務使得組件不用去服務器獲取數據、進行驗證……,這一切都可以通過服務完成。
組件的任務就是提供用戶體驗,僅此而已!
它介於視圖(由模板渲染)和應用邏輯(包括模型)之間。
設計良好的組件為數據綁定提供屬性和方法,對它們不重要的事情委托給服務。
依賴註入
依賴註入是提供類的新實例的一種方式,負責處理好類所需的全部依賴(服務)。
Angular 使用依賴註入提供我們需要的組件及組件所需的服務。
Angular 能通過查看構造函數的參數類型,來的值組件所需的服務。
示例:
// app/hero-list.component.ts constructor(private service: HeroService) { }
構造函數的參數提到瞭一個服務。
當 Angular 創建組件時,會先為組件所需的服務找一個註入器(Injector)。
註入器是一個維護服務實例的容器,存放著以前創建的實例。如果容器中還沒有所請求的服務實例,註入器就會創建一個服務實例,並且添加到容器中,然後把這個服務返回給 Angular。當所有服務都被解析完並返回, Angular 會以這些服務為參數去調用組件的構造函數,這就是依賴註入。
也就是說服務是先於組件被執行的。它先處理所有的服務到一個倉庫,然後再處理組件,組件需要哪個服務就從倉庫取出來給你。
提供商添加到根模塊,在任何地方使用的都是服務的同一個實例:
// app/app.module.ts providers: [ BackendService, HeroService, Logger ],
提供商是確定處理組件之前必須存在所依賴的組件
也可以把它註冊到組件層:
// app/hero-list.component.ts @Component({ moduleId: module.id, selector: 'hero-list', templateUrl: 'hero-list.component.html', providers: [ HeroService ] })
添加到裝飾器元數據的屬性中。
依賴註入的要點:
依賴註入滲透在整個Angular框架中 註入器是機制的核心
註入器負責維護一個容器,存放創建過的服務實例 註入器能使用提供商創建一個新的服務實例 提供商是一個用於創建服務的配方。 把提供商註冊到註入器。