AngularDart4.0 指南- 模板語法一

學習如何編寫顯示數據並在數據綁定的幫助下使用用戶事件的模板。
Angular應用程序管理用戶看到和能夠作的事情,經過組件類實例(組件)和麪向用戶的模板的交互來實現這一點。
您能夠熟悉模型 - 視圖 - 控制器(MVC)或模型 - 視圖 - 視圖模型(MVVM)的組件/模板。 在Angular中,組件扮演控制器/視圖模型的一部分,模板表示視圖。html

內容

本指南涵蓋了Angular模板語法的基本元素,以及構建視圖所需的元素:java

  • 模板中的HTML
  • 插值({{...}})
  • 模板表達式
  • 模板語句
  • 綁定語法
  • 屬性綁定([property])
  • 屬性,類和樣式綁定
  • 事件綁定((event))
  • 雙向數據綁定([(...)])
  • 內置指令
  • 內置的屬性指令
  •       NgClass
  •       NgStyle
  •       NgModel ([(ngModel)])
  • 內置結構指令
  •      NgIf
  •      NgFor
  •           模板輸入變量
  •           Microsyntax
  •     NgSwitch指令
  • 模板引用變量(#var)
  • 輸入和輸出屬性(@Input和@Output)
  • 模板表達式運算符
  •     管道(|)
  •     安全導航操做員(?.)

現成示例(查看源代碼)演示了本指南中描述的全部語法和代碼片斷。git

模板中的HTML

HTML是Angular模板的語言。 幾乎全部的HTML語法都是有效的模板語法。 <script>元素是一個值得注意的例外。 這是被禁止的,消除腳本注入攻擊的風險。 在實踐中,<script>被忽略,並在瀏覽器控制檯中出現警告。 有關詳情,請參閱安全性頁面。github

一些合法的HTML在模板中沒有多大意義。 <html><body><base>元素沒有用處。 剩下一切都是一致的。web

您可使用組件和指令出現的新元素和屬性來擴展模板的HTML詞彙表。 在下面的章節中,您將學習如何經過數據綁定來動態獲取和設置DOM(文檔對象模型)值。express

從數據綁定插值的第一種形式開始,看看有多少更豐富的模板HTML可使用。請回到頂部。api

插值({{...}})

在Angular的早期教程中,你遇到了插值的雙曲括號{{and}}瀏覽器

<p>My current hero is {{currentHero.name}}</p>

您可使用插值將計算的字符串組織到HTML元素標記和屬性賦值之間的文本中。緩存

<h3>
  {{title}}
  <img src="{{heroImageUrl}}" style="height:30px">
</h3>

大括號裏的文本一般是組件屬性的名稱。 Angular用相應的屬性值替換該名稱。 在上面的例子中,Angular評估了titleheroImageUrl屬性,並「填充空白」,首先直接顯示一個應用標題,而後是一個英雄圖像。安全

更多的,大括號之間的文本是一個模板表達式,Angular首先評估並轉換爲一個字符串, 經過添加這兩個數字來進行如下內插:

<!-- "The sum of 1 + 1 is 2" -->
<p>The sum of 1 + 1 is {{1 + 1}}</p>

該表達式能夠調用主機的方法,例如getVal(),以下所示:

<!-- "The sum of 1 + 1 is not 4" -->
<p>The sum of 1 + 1 is not {{1 + 1 + getVal()}}</p>

Angular用雙曲花括號評估全部表達式,將表達式結果轉換爲字符串,並將它們與相鄰的文字串相連接。最後,它將這個複合插值結果賦值給一個元素指令屬性

您彷佛在元素標記之間插入結果並將其分配給屬性。這麼想很方便,你會由於這個錯誤而受苦。雖然這不徹底正確。插值是收斂到屬性綁定中的一種特殊語法,以下所述。

但首先,讓咱們仔細看看模板表達式和語句。

模板表達式

模板表達式產生一個值。 Angular執行表達式並將其分配給綁定目標的屬性; 目標多是HTML元素,組件或指令。

{{1 + 1}}中的內插大括號包圍模板表達式1 + 1.在下面的屬性綁定部分中,在[property] =「expression」中,模板表達式顯示在符號右側的引號中。

你用相似Dart的語言編寫這些模板表達式。 許多Dart表達式是合法的,但不是所有。

帶有或促進反作用的Dart表達式是被禁止的,包括:

  • 賦值(=,+ =, - =,...
  • new const
  • 連接表達式;
  • 遞增和遞減運算符(++- -

與Dart語法的其餘顯着差別包括:

不支持Dart字符串插值; 例如,而不是「'The title is $title'」,你必須寫''The title is ' + title'「
不支持按位運算符| &
新的模板表達式運算符,如|

表達式上下文

表達式上下文一般是組件實例。 在如下片斷中,雙花括號內的標題和引號中的isUnchanged引用了AppComponent的屬性。

{{title}}
<span [hidden]="isUnchanged">changed</span>

一個表達式也能夠用來引用模板上下文的屬性,包括模板輸入變量(let hero)或模板引用變量(#heroInput)。

<div *ngFor="let hero of heroes">{{hero.name}}</div>
<input #heroInput> {{heroInput.value}}

表達式中術語的上下文是模板變量和組件成員的混合。 若是引用這些名稱空間的名稱,則模板變量名稱優先,後面是指令的上下文,最後是組件的成員名稱。

前面的例子顯示了這樣一個名字衝突。 該組件具備hero屬性,而* ngFor定義了英雄模板變量。 {{hero.name}}中的英雄是指變量輸入變量,而不是組件的屬性。
模板表達式不能引用靜態屬性,也不能引用頂層變量或函數,如來自dart:htmlwindow document 。他們不能直接調用從dart:math導入的print或函數。 它們僅限於引用表達式上下文的成員。

表達式準則

模板表達式能夠構建或破壞應用程序。 請遵循如下準則:

這些指導方針的例外狀況應該是在你理解的狀況下。

沒有明顯的反作用

模板表達式不該該更改目標屬性的值之外的任何應用程序狀態。

這個規則對Angular的「單向數據流」策略是必不可少的。您沒必要擔憂讀取組件值可能會改變一些其餘的顯示值。這個視圖在整個渲染過程當中應該是穩定的。

快速執行

Angular在每一個更改檢測週期後執行模板表達式。 更改檢測週期由許多異步活動觸發,如承諾的分辨率,http結果,計時器事件,按鍵和鼠標移動。

表達式應該快速完成,不然用戶可能會遇到卡幀,尤爲是在較慢的設備上。 當他們的計算成本很高時,考慮緩存值。

簡單

雖然能夠編寫至關複雜的模板表達式,可是應該避免使用它們。

屬性名稱或方法調用應該是標準。 偶爾的布爾否認(!)能夠。
 另外, 將應用和業務邏輯放到到組件自己,在那裏它將更容易開發和測試。

冪等性

冪等表達式是理想的,由於它沒有反作用,而且改善了Angular的變化檢測性能。

對Angular來講,一個冪等表達式老是返回徹底相同的東西,直到它的一個依賴值發生變化。

在事件循環的一個回合期間,依賴值不該該改變。若是一個冪等表達式返回一個字符串或一個數字,當它在一行中調用兩次時會返回相同的字符串或數字。若是表達式返回一個對象(包括一個List),它將在連續調用兩次時返回相同的對象引用。

模板語句

模板語句響應綁定目標(例如元素,組件或指令)引起的事件。 您會在事件綁定部分看到模板語句,並在(event)=「statement」中出如今=符號右側的引號中。

<button (click)="deleteHero()">Delete hero</button>

模板語句有一方面的做用。 它是一個事件的所有。 就是如何從用戶操做更新應用程序狀態。

響應事件是Angular的「單向數據流」的另外一面。在事件循環的這個週期中,您能夠自由地在任何地方進行全部更改。

像模板表達式同樣,模板語句使用了一種看起來像Dart的語言。 模板語句解析器與模板表達式解析器不一樣,特別支持基本的賦值(=)和連接表達式(with;)

可是,某些Dart語法是不容許的:

  • new const
  • 遞增和遞減運算符,++ --
  • 賦值運算符,例如 +=-=
  • 按位運算符| &
  • 模板表達式運算符

語句上下文

與表達式同樣,語句只能引用語句上下文中的內容,例如組件實例的事件處理方法。

語句上下文一般是組件實例。 (click)=「deleteHero()」中的deleteHero是數據綁定組件的一種方法。

<button (click)="deleteHero()">Delete hero</button>

語句上下文也能夠引用模板本身的上下文的屬性。 在如下示例中,將模板$ event對象,模板輸入變量(let hero)和模板引用變量#heroForm)傳遞給組件的事件處理方法。

<button (click)="onSave($event)">Save</button>
<button *ngFor="let hero of heroes" (click)="deleteHero(hero)">{{hero.name}}</button>
<form #heroForm (ngSubmit)="onSubmit(heroForm)"> ... </form>

模板上下文字段優先於組件上下文字段。 在上面的deleteHero(hero)中,hero是模板輸入變量,而不是組件的hero屬性。

模板語句不能引用類的靜態屬性,也不能引用頂層變量或函數,如來自dart:htmlwindowdocument 。 它們不能直接調用從dart:math導入的print或函數。

聲明準則

與表達式同樣,避免編寫複雜的模板語句。 方法調用或簡單的屬性分配應該是標準。
如今您已經感受到了模板表達式和語句,您已經準備好了解超越插值的各類數據綁定語法。

綁定語法:概述

數據綁定是一種協調用戶看到應用程序數據值的機制。 雖然您能夠將值推送到HTML中,並從HTML中提取值,可是若是將這些瑣事轉換爲綁定框架,則應用程序更易於編寫,讀取和維護。 您只需聲明綁定源和目標HTML元素之間的綁定,而後讓框架完成工做。

Angular提供了多種數據綁定。 本指南涵蓋了大部分的Angular數據綁定及其語法的高級使用。

綁定類型能夠按照數據流的方向分爲三類:source-to-viewview-to-source,以及雙向順序:view-to-source-to-view

數據方向 語法 類型

單向

從數據源到目標視圖

{{expression}}
[target]="expression"
bind-target="expression"

 

插值

組件屬性

元素屬性

元素類

元素樣式

單向

從目標視圖到數據源

(target)="statement"
on-target="statement"

 

事件
雙向
[(target)]="expression"
bindon-target="expression"

 

雙向

除插值之外的綁定類型在等號左邊或者用標點符號([]())包圍,或者帶前綴(bind-on-bindon-)都有一個目標名稱。

目標名稱是一個屬性的名稱。 它可能看起來像一個元素屬性的名稱,但它不是。 爲了體會差別性,您必須開發一種思考HTML模板的新方法。

一種新的心智模式

藉助數據綁定的全部功能以及使用自定義標記擴展HTML詞彙表的能力,將HTML模板視爲HTML Plus是頗有誘惑力的

它確實是HTML Plus。 可是它也與你習慣的HTML有很大的不一樣。 它須要一個新的心智模式。
在HTML開發的正常過程當中,您可使用HTML元素建立一個可視結構,並經過使用字符串常量設置元素屬性來修改這些元素。

<div class="special">Mental Model</div>
<img src="assets/images/hero.png">
<button disabled>Save</button>

您仍然在Angular模板中以這種方式建立結構並初始化屬性值。
而後,您將學習如何使用封裝了HTML的組件建立新元素,並將它們放入模板中,就好像它們是原生HTML元素同樣。

<!-- Normal HTML -->
<div class="special">Mental Model</div>
<!-- Wow! A new element! -->
<hero-detail></hero-detail>

這是HTML Plus。
而後你學習數據綁定。 你遇到的第一個綁定多是這樣的:

<!-- Bind button disabled state to `isUnchanged` property -->
<button [disabled]="isUnchanged">Save</button>

你的直覺可能代表你綁定了按鈕的disabled屬性,並將其值設置爲組件的isUnchanged屬性的當前值。 那個直覺是不正確的!

平常的HTML心智模式是誤導性的。 一旦你開始數據綁定,你再也不使用HTML Attributes 。 你不是設置屬性(Attributes) ; 你應該設置DOM元素,組件和指令的屬性(Properties)

HTML屬性(Attributes)與DOM屬性(Properties)

HTML屬性和DOM屬性的區別對於理解Angular綁定是如何工做是相當重要的。
Attributes 由HTML定義。Properties 由DOM(文檔對象模型)定義。

  • 一些HTML屬性(Attributes)映射到屬性(Properties)1:1, id是一個例子。
  • 一些HTML屬性(Attributes)沒有相應的屬性(Properties)。 colspan就是一個例子。
  • 一些DOM屬性(Properties)沒有相應的屬性(Attributes)。 textContent就是一個例子。
  • 許多HTML屬性(Attributes)彷佛映射到屬性(Properties)...但不是以你想象的方式!

最後一個類別含義模糊的,除非你知道這個通常規則:

屬性(Attributes)初始化DOM屬性(Properties),而後完工。 屬性(Properties)值能夠會改變; 屬性(Attributes)值不能。

例如,當瀏覽器呈現<input type =「text」 value =「Bob」>時,它會建立一個對應的DOM節點,其值屬性(Properties)已初始化爲「Bob」。

當用戶在輸入框中輸入「Sally」時,DOM元素值屬性變爲「Sally」。 可是,HTML value屬性保持不變,當訪問輸入元素的該屬性:input.getAttribute('value')返回「Bob」。

HTML屬性(Attributes) value指定初始值; DOM value屬性(Properties)是當前值。

disabled 屬性(Attributes)是另外一個特殊的例子。 按鈕的disabled 屬性(Properties)默認爲false,所以按鈕已啓用。 當您添加disabled屬性(Attributes)時,它的存在會將按鈕的disabled屬性(Properties)初始化爲true,所以該按鈕被禁用。

添加和刪除disabled屬性(Attributes)將禁用和啓用該按鈕。
該屬性(Attributes)的值是可有可無的,這就是爲何您不能經過編寫<button disabled =「false」> Still Disabled </ button>來啓用按鈕的緣由。

設置按鈕的disabled屬性(Properties)(例如,使用Angular綁定)禁用或啓用按鈕。屬性(Properties)的值很重要。

HTML屬性(Attributes)和DOM屬性(Properties)是不同的,即便它們具備相同的名稱。

這個事實值得重複:模板綁定使用屬性(properties)和事件(events)發揮做用,而不是屬性(attributes)。

一個沒有屬性的世界

在Angular的世界中,屬性(attributes)的惟一做用是初始化元素和指令狀態。 當你寫數據綁定時,你只處理目標對象的屬性(properties)和事件(events)。 HTML屬性(attributes)不起做用。

記住這個模型,繼續閱讀以瞭解綁定目標。

綁定目標

數據綁定的目標是DOM中的東西。根據綁定類型,目標能夠是(element | component |directive)屬性,(element | component | directive)事件或(不多)屬性(attributes)名稱。 下表總結了這些狀況:

Type Target Example
Property Element property
Component property
Directive property
<img [src]="heroImageUrl">
<hero-detail [hero]="currentHero"></hero-detail>
<div [ngClass]="{special: isSpecial}"></div>

 

Event Element event
Component event
Directive event
<button (click)="onSave()">Save</button>
<hero-detail (deleteRequest)="deleteHero()"></hero-detail>
<div (myClick)="clicked=$event" clickable>click me</div>

 

Two-way Event and property
<input [(ngModel)]="name">

 

Attribute Attribute (例外)
<button [attr.aria-label]="help">help</button>

 

Class class property
<div [class.special]="isSpecial">Special</div>

 

Style style property
<button [style.color]="isSpecial ? 'red' : 'green'">

 

您如今已經準備好詳細查看綁定類型。

屬性綁定([property])

編寫一個模板屬性綁定來設置一個視圖元素的屬性。 該綁定將該屬性設置爲模板表達式的值。

最多見的屬性綁定將元素屬性設置爲組件屬性值。一個示例是將圖像元素的src屬性綁定到組件的heroImageUrl屬性:

<img [src]="heroImageUrl">

另外一個例子是當組件標識isUnchanged的時候禁用一個按鈕:

<button [disabled]="isUnchanged">Cancel is disabled</button>

另外一個是設置一個指令的屬性:

<div [ngClass]="classes">[ngClass] binding to the classes property</div>

另外一個是設置自定義組件的模型屬性(父組件和子組件進行通訊的一個好方法):

<hero-detail [hero]="currentHero"></hero-detail>

單向

人們一般將屬性綁定描述爲單向數據綁定,由於它從一個組件的數據屬性向一個目標元素屬性傳遞一個值。

您不能使用屬性綁定將值從目標元素中拉出。 您不能綁定到目標元素的屬性來讀取它。 你只能設置它。

一樣,您不能在目標元素上使用屬性綁定來調用方法。

若是元素引起事件,則可使用事件綁定來監聽它們。

若是您必須讀取目標元素屬性或調用其中一個方法, 你須要一個不一樣的技術。 查看ViewChildContentChild的API參考。

綁定目標

方括號之間的元素屬性標識目標屬性。 如下代碼中的目標屬性是圖像元素的src屬性。

<img [src]="heroImageUrl">

有些人更喜歡綁定前綴bind-替代,稱爲規範形式:

<img bind-src="heroImageUrl">

目標名稱始終是屬性(property)的名稱,即便它看起來是別的名稱。 你可能會看到src,並認爲它是一個屬性(attribute)的名稱。 不是; 這是一個圖像元素屬性(property)的名稱。

元素屬性(property)多是更常見的目標,但Angular首先查看名稱是不是已知指令的屬性(property),以下例所示:

<div [ngClass]="classes">[ngClass] binding to the classes property</div>

從技術上講,Angular將名稱與指令輸入或用@Input()裝飾的屬性相匹配。 這樣的輸入映射到指令本身的屬性。

若是名稱未能匹配已知指令或元素(property)的屬性,則Angular會報告「未知指令」錯誤。

避免反作用

如前所述,模板表達式的評估必須沒有可見的反作用。表達式語言自己是爲了保證您的安全。您不能爲屬性綁定表達式中的任何東西賦值,也不能使用增量和減量運算符。

固然,該表達式可能會調用具備反作用的屬性或方法。 Angular沒法知道或阻止你。

該表達式能夠調用相似getFoo()的東西。 只要你知道getFoo()是作什麼的。若是getFoo()改變了某些東西,並且碰巧綁定了某些東西,你將冒着必定的風險。Angular可能會或可能不會顯示更改的值。Angular可能會檢測到更改併發出警告錯誤。一般來講,保留數據屬性和方法返回值就夠了。

返回適當的類型

模板表達式應經過目標屬性計算預期值的類型:

  • 若是目標屬性須要一個字符串,則返回一個字符串。
  • 若是目標屬性指望一個數字,則返回一個數字。
  • 若是目標屬性須要一個對象,則返回一個對象。

HeroDetail組件的hero屬性須要一個Hero對象,這正是你在屬性綁定中發送的內容: 

<hero-detail [hero]="currentHero"></hero-detail>

檢查模式異常

在檢查模式下,若是模板表達結果類型和目標屬性類型不是賦值兼容的,則會拋出一個類型異常。 有關檢查模式的信息,請參閱Dart語言指南中的重要概念

Dart 2.0注意:檢查模式不會出如今飛鏢2.0。 有關更多信息,請參閱Dart 2.0更新

記住括號


括號告訴Angular評估模板表達式。 若是省略方括號,Angular會將該字符串視爲常量,並使用該字符串初始化目標屬性。 它不評估字符串!
不要犯如下錯誤:

<!-- ERROR: A value of type 'String' can't be assigned to a variable of type 'Hero'.
<hero-detail hero="currentHero"></hero-detail>
-->

檢查模式類型異常例子

在檢查模式下,上面的代碼將致使一個類型異常:String不是Hero的子類型。

一次性字符串初始化

知足如下全部條件時,省略括號:

  • 目標屬性接受一個字符串值。
  • 該字符串是一個固定的值,您能夠拷貝到模板中。
  • 這個初始值永遠不會改變。

一次性字符串初始化在標準HTML中是常規的,而且它對於指令和組件屬性也一樣適用。 如下示例將HeroDetailComponentprefix屬性初始化爲固定字符串,而不是模板表達式。 Angular設置它並再也不管它。

<hero-detail prefix="You are my" [hero]="currentHero"></hero-detail>

另外一方面,[hero]綁定仍然保留對組件的currentHero屬性的有效綁定。

屬性綁定或插值?

你常常有插值和屬性綁定的選擇。 如下綁定作一樣的事情:

<p><img src="{{heroImageUrl}}"> is the <i>interpolated</i> image.</p>
<p><img [src]="heroImageUrl"> is the <i>property bound</i> image.</p>

<p><span>"{{title}}" is the <i>interpolated</i> title.</span></p>
<p>"<span [innerHTML]="title"></span>" is the <i>property bound</i> title.</p>

在許多狀況下插值是屬性綁定較爲方便的替代品。
將數據值呈現爲字符串時,沒有技術上的理由去選擇另外一種形式,但插值更可讀。咱們建議創建編碼風格規則,選擇符合規則的形式,對於手頭的任務來講是最天然的
將元素屬性設置爲非字符串數據值時,必須使用屬性綁定。

內容安全

想象下面的惡意內容。

String evilTitle =
    'Template <script>alert("evil never sleeps")</script>Syntax';

幸運的是,Angular數據綁定對危險的HTML進行了警報。 它在顯示它們以前清理這些值。 它不容許帶腳本標記的HTML泄露到瀏覽器中,既不能使用插值也不能使用屬性綁定。

<!--
  Angular generates warnings for these two lines as it sanitizes them
  WARNING: sanitizing HTML stripped some content (see http://g.co/ng/security#xss).
 -->
<p><span>"{{evilTitle}}" is the <i>interpolated</i> evil title.</span></p>
<p>"<span [innerHTML]="evilTitle"></span>" is the <i>property bound</i> evil title.</p>

插值處理腳本標記與屬性綁定不一樣,但兩種方法均無害地呈現內容。

屬性(Attribute),類和樣式綁定

模板語法爲不太適合屬性(property )綁定的場景提供了專門的單向綁定。

屬性(Attribute)綁定

您能夠直接使用屬性綁定來設置屬性的值。

這是綁定設置目標屬性(property)的惟一例外規則。 這是建立和設置屬性(attribute)的惟一一種綁定。

本指南反覆強調,使用屬性(property)綁定設置元素屬性(property)始終優先於使用字符串設置屬性(attribute)。 Angular爲何提供屬性(attribute)綁定?

當沒有要綁定的元素屬性時,必須使用屬性綁定。

考慮ARIASVGtable span屬性。 他們是純粹的屬性。 它們不對應元素屬性,也不設置元素屬性。 沒有屬性目標綁定。

在寫像這樣的東西時,這個事實變得很是明顯:

<tr><td colspan="{{1 + 1}}">Three-Four</td></tr>

結果是這個錯誤:

Template parse errors:
Can't bind to 'colspan' since it isn't a known native property

正如消息所述,<td>元素沒有colspan屬性。 它具備「colspan」屬性(attribute),可是插值和屬性(attribute)綁定只能設置屬性(properties),而不能設置屬性(attribute)。

您須要屬性(attribute)綁定來建立和綁定到這些屬性(attribute)。

屬性(attribute)綁定語法相似於屬性(properties)綁定。之前綴attr開頭,後跟一個點(.)和屬性名稱代替括號之間的元素屬性。而後使用解析爲字符串的表達式來設置屬性值。

[attr.colspan]綁定到計算值:

<table border=1>
  <!--  expression calculates colspan=2 -->
  <tr><td [attr.colspan]="1 + 1">One-Two</td></tr>

  <!-- ERROR: There is no `colspan` property to set!
    <tr><td colspan="{{1 + 1}}">Three-Four</td></tr>
  -->

  <tr><td>Five</td><td>Six</td></tr>
</table>

如下是表格的呈現方式:

屬性(attribute)綁定的主要用例之一是設置ARIA屬性,以下例所示:

<!-- create and set an aria attribute for assistive technology -->
<button [attr.aria-label]="actionName">{{actionName}} with Aria</button>
相關文章
相關標籤/搜索