AngularDart(咱們一般在這個文檔中簡單地稱爲Angular)是一個框架,用於在HTML和Dart中構建客戶端應用程序。它是做爲Angular包發佈的,與 其餘許多Dart包同樣,能夠經過Pub工具得到。html
您能夠經過使用Angular的標記組合HTML 模板,編寫組件類來管理這些模板,在服務中添加應用程序邏輯以及在模塊中裝入組件和服務來編寫Angular應用程序。java
而後,經過引導根模塊啓動應用程序。 Angular接管,根據您提供的說明在瀏覽器中呈現您的應用內容,並響應用戶交互。
固然,除此以外還有更多。 您將在後面的頁面中瞭解詳細信息。 如今就着眼於大局。git
架構圖標識了Angular應用程序的八個主要構建塊:程序員
瞭解這些積木,你就在路上。github
Angular應用程序是模塊化的; 也就是說,應用程序由許多模塊組裝而成。api
在本指南中,術語module是指Dart編譯單元,例如庫或包。 若是Dart文件除去library或part命令,那麼該文件自己就是一個庫,所以也是一個編譯單元。有關編譯單元的更多信息,請參閱Dart語言規範中的「庫和腳本」一章。瀏覽器
每一個Angular應用程序至少有一個模塊,即根模塊。 雖然根模塊多是小應用程序中的惟一模塊,但大多數應用程序都有更多的功能模塊,每一個模塊都是專用於應用程序域,工做流程或緊密相關的一組功能的一致代碼塊。服務器
最簡單的根模塊定義了一個單獨的根組件類,例如:lib / app_component.dart(class)架構
class AppComponent {}
按照慣例,根組件的名稱是AppComponent。
Angular全體就像是Angular包內的庫的集合。 主要的Angular庫是angular,大多數app模塊導入以下:
import 'package:angular/angular.dart';
Angular包有其餘重要的庫,如angular.security。
一個組件控制屏幕中的一小塊視圖。
例如,如下視圖由組件控制:
您能夠在一個類中定義一個組件的應用程序邏輯 - 它支持視圖的功能。 該類經過屬性和方法的API與視圖交互。
例如,這個HeroListComponent有一個heroes屬性,返回從服務中獲取的英雄列表。 HeroListComponent還有一個selectHero()方法,當用戶點擊從列表中選擇一個英雄時,它會設置一個selectedHero屬性。lib/src/hero_list_component.dart (class)
class HeroListComponent implements OnInit { List<Hero> heroes; Hero selectedHero; final HeroService _heroService; HeroListComponent(this._heroService); void ngOnInit() { heroes = _heroService.getHeroes(); } void selectHero(Hero hero) { selectedHero = hero; } }
Angular建立,更新和銷燬組件如同用戶在應用程序中行走。 您的應用程序能夠經過可選的生命週期掛鉤在今生命週期中的每一個時刻採起行動,如上面聲明的ngOnInit()。
您可使用其配套模板定義組件的視圖。 模板是一種HTML形式,告訴Angular如何呈現組件。
模板看起來像普通的HTML,除了一些不一樣之處。 這是咱們的HeroListComponent的一個模板:
lib/src/hero_list_component.html
<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> <hero-detail *ngIf="selectedHero != null" [hero]="selectedHero"></hero-detail>
雖然這個模板使用了典型的HTML元素,如<h2>和<p>,但它也有一些不一樣之處。 相似於* ngFor,{{hero.name}},(click),[hero]和<hero-detail>的代碼使用Angular的模板語法。
在模板的最後一行,<hero-detail>標籤是一個自定義元素,表明一個新的組件HeroDetailComponent。
HeroDetailComponent是與您正在審閱的HeroListComponent不一樣的組件。 HeroDetailComponent(代碼未顯示)顯示關於特定英雄的詳情,這是用戶從HeroListComponent提供的列表中選擇的英雄。 HeroDetailComponent是HeroListComponent的一個子項。
注意<hero-detail>是如何在原生HTML元素中合適的存放。 自定義組件與原生HTML在相同的佈局中無縫混合。
元數據告訴Angular如何處理一個類。
回顧HeroListComponent的代碼,你能夠看到它只是一個類。 沒有一個框架的痕跡,沒有Angular的特定代碼。
實際上,HeroListComponent實際上只是一個類。 直到你告訴Angular它是一個組件。要告訴Angular HeroListComponent是一個組件,請將元數據附加到該類。在Dart中,您可使用註解附加元數據。
如下是HeroListComponent的一些元數據,@Component註解標識緊接着它下面的類做爲一個組件類:
lib/src/hero_list_component.dart (metadata)
@Component( selector: 'hero-list', templateUrl: 'hero_list_component.html', directives: const [CORE_DIRECTIVES, formDirectives, HeroDetailComponent], providers: const [HeroService], ) class HeroListComponent implements OnInit { // ··· }
註解一般具備配置參數。 @Component註解須要參數提供Angular須要的信息來建立和呈現組件及其視圖。
如下是一些可能的@Component參數:
@Component中的元數據告訴Angular從哪裏獲取爲組件指定的主要構建塊。
模板,元數據和組件一塊兒描述一個視圖。
以相似的方式應用其餘元數據註解以指導Angular行爲。 @Injectable,@Input和@Output是一些比較流行的註解。
建築外包是你必須添加元數據到你的代碼,以便Angular知道該怎麼作。
若是沒有框架,您將負責將數據值推送到HTML控件中,並將用戶響應轉化爲操做和值更新。 用手寫這樣的推/拉邏輯是單調乏味,容易出錯的,並且像任何經驗豐富的jQuery程序員都能證實的那樣是一場惡夢。
Angular支持數據綁定,這是一種協調模板部分與組件部分的機制。 添加綁定標記到模板HTML告訴Angular如何鏈接雙方。
如圖所示,有四種形式的數據綁定語法。 每一個表單都有一個方向 - 從DOM到DOM,或者在兩個方向。
HeroListComponent示例模板有三種形式:
lib / src / hero_list_component.html(binding)
<li>{{hero.name}}</li> <hero-detail [hero]="selectedHero"></hero-detail> <li (click)="selectHero(hero)"></li>
雙向數據綁定是一個重要的第四種形式,它使用ngModel指令將屬性和事件綁定在一個符號中。 如下是HeroDetailComponent模板的一個例子:lib/src/hero_detail_component.html (ngModel)
<input [(ngModel)]="hero.name">
在雙向綁定中,與屬性綁定同樣,數據屬性值將從組件輸入到輸入框中。 用戶的更改也會返回到組件,將屬性重置爲最新值,就像事件綁定同樣。
Angular在每一個JavaScript事件循環中處理全部數據綁定,從應用程序組件樹的根到全部子組件。
數據綁定在模板及其組件之間的通訊中起着重要的做用。
數據綁定對於父組件和子組件之間的通訊也很重要。
Angular模板是動態的。 當Angular呈現它們時,它根據指令給出的指示轉換DOM。
指令是一個帶有@Directive註解的類。 一個組件是一個指令與模板; 一個@Component註解其實是一個@Directive註解,擴展了面向模板的特性。
雖然組件在技術上是指令,但組件對於Angular應用程序來講是很是獨特和重要的,因此這種架構概述將組件與指令分開。
還有其餘兩種指令:結構和屬性指令。
它們傾向於以屬性的形式出如今元素標籤內,有時候以名稱的形式出現,但更常見的是做爲賦值或綁定的目標。
結構指令經過添加,刪除和替換DOM中的元素來改變佈局。
示例模板使用兩個內置的結構指令:
lib / src / hero_list_component.html(structural)
<li *ngFor="let hero of heroes"></li> <hero-detail *ngIf="selectedHero != null"></hero-detail>
在Dart中,惟一值爲true的是布爾值true; 全部其餘值是錯誤的。 JavaScript和TypeScript相反,將諸如1和大多數非空對象的值視爲true。 出於這個緣由,這個應用程序的JavaScript和TypeScript版本可使用selectedHero做爲* ngIf表達式的值。 Dart版本必須使用布爾運算符!=替換。
屬性指令會改變現有元素的外觀或行爲。 在模板中,它們看起來像常規的HTML屬性,所以也就是名稱。
實現雙向數據綁定的ngModel指令是一個屬性指令的例子。 ngModel經過設置其顯示值屬性並響應更改事件來修改現有元素(一般是<input>)的行爲。lib/src/hero_detail_component.html (ngModel)
<input [(ngModel)]="hero.name">
Angular還有一些指令能夠改變佈局結構(例如,ngSwitch)或修改DOM元素和組件的方面(例如ngStyle和ngClass)。
固然,你也能夠編寫你本身的指令。 像HeroListComponent這樣的組件是一種自定義指令。
服務是一個普遍的類別,包含您的應用程序所需的任何值,功能或特徵。
幾乎任何東西均可以成爲服務。 服務一般是一個狹義的,明確的目的。 它應該作一些具體的事情,並作好。
例子包括:
Angular中沒有特別指定服務。 Angular沒有定義服務。 沒有服務基礎類,沒有地方註冊服務。
然而,服務是任何Angular的應用程序的基礎。 組件佔據了服務的半壁江山。
如下是一個輸出到瀏覽器控制檯的日誌服務類的示例:lib/src/logger_service.dart (class)
class Logger { void log(Object msg) => window.console.log(msg); void error(Object msg) => window.console.error(msg); void warn(Object msg) => window.console.warn(msg); }
這是一個HeroService,使用Future來獲取英雄。 HeroService取決於日誌服務和另外一個處理服務器頻繁通訊工做的BackendService。
lib / src / hero_service.dart(class)
class HeroService { final BackendService _backendService; final Logger _logger; final heroes = <Hero>[]; HeroService(this._logger, this._backendService); List<Hero> getHeroes() { _backendService.getAll(Hero).then((heroes) { _logger.log('Fetched ${heroes.length} heroes.'); this.heroes.addAll(heroes as List<Hero>); // fill cache }); return heroes; } }
服務無處不在。
組件類應該是精益的。 他們不從服務器獲取數據,驗證用戶輸入或直接登陸到控制檯。 他們將這些任務委託給服務。
一個組件的工做是啓用用戶體驗,僅此而已。 它在視圖(由模板呈現)和應用程序邏輯(一般包括模型的一些概念)之間起中介做用。 一個好的組件提供了數據綁定的屬性和方法。 它委託一切不重要的服務。
Angular不強制執行這些原則。 若是您用3000行代碼編寫「kitchen sink」組件,它不會抱怨。
Angular經過簡單地將應用程序邏輯分解爲服務,並經過依賴注入將這些服務提供給組件,從而幫助您遵循這些原則。
依賴注入是一種提供一個類的新實例的方法,它須要完整的依賴關係。 大多數依賴是服務。 Angular使用依賴注入來爲新組件提供他們須要的服務。
Angular能夠經過查看構造函數參數的類型來判斷組件須要哪些服務。 例如,你的HeroListComponent的構造函數須要一個HeroService:lib/src/hero_list_component.dart (constructor)
final HeroService _heroService; HeroListComponent(this._heroService);
當Angular建立一個組件時,它首先要求一個注入器來提供組件須要的服務。
注入器維護一個先前建立的服務實例的容器。 若是請求的服務實例不在容器中,那麼在將服務返回給Angular以前,注入器將建立一個並將其添加到容器中。 當全部請求的服務已經解析並返回時,Angular能夠用這些服務做爲參數調用組件的構造函數。 這是依賴注入。
HeroService注入的過程看起來有點像這樣:
若是注射器沒有HeroService,它如何知道如何製做一個?
簡而言之,您必須事先在注入器中註冊HeroService的提供者。 提供者是能夠建立或返回服務的東西,一般是服務類自己。
不管應用程序組件樹中的級別如何,您均可以在引導期間或組件中註冊提供程序。
註冊提供者最多見的方法是使用@Component註解providers參數在組件級別:lib/app_component.dart
@Component( // ··· providers: const [BackendService, HeroService, Logger], ) class AppComponent {}
使用組件註冊意味着您將得到該組件的每一個新實例的服務新實例。 經過組件提供的服務與應用程序組件樹中的全部組件的後代共享。
引導時註冊提供程序的狀況很是少見。 有關詳細信息,請參閱依賴注入頁面的配置注入部分。
關於依賴注入的要點:
包起來
您已經瞭解了關於Angular應用程序的八個主要構建塊的基礎知識:
這是一個Angular應用程序中全部其餘應用程序的基礎,並且這足夠了。但它並不包括你須要知道的一切。
如下是其餘重要的Angular功能和服務的簡短字母順序列表。