日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

angular2的模板语法

發(fā)布時(shí)間:2025/4/9 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 angular2的模板语法 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Angular 應(yīng)用管理著用戶之所見和所為,并通過 Component 類的實(shí)例(組件)和面向用戶的模板來與用戶交互。

從使用模型-視圖-控制器 (MVC) 或模型-視圖-視圖模型 (MVVM) 的經(jīng)驗(yàn)中,很多開發(fā)人員都熟悉了組件和模板這兩個(gè)概念。 在 Angular 中,組件扮演著控制器或視圖模型的角色,模板則扮演視圖的角色。

來看看寫視圖的模板都需要什么。本章將覆蓋模板語法中的下列基本元素

HTML 是 Angular 模板的語言。快速起步應(yīng)用的模板是純 HTML 的:

<h1>Hello Angular</h1>

幾乎所有的 HTML 語法都是有效的模板語法。但值得注意的例外是<script>元素,它被禁用了,以阻止腳本注入攻擊的風(fēng)險(xiǎn)。(實(shí)際上,<script>只是被忽略了。)

有些合法的 HTML 被用在模板中是沒有意義的。<html>、<body>和<base>元素這個(gè)舞臺(tái)上中并沒有扮演有用的角色。基本上所有其它的元素都被一樣使用。

可以通過組件和指令來擴(kuò)展模板中的 HTML 詞匯。它們看上去就是新元素和屬性。接下來將學(xué)習(xí)如何通過數(shù)據(jù)綁定來動(dòng)態(tài)獲取/設(shè)置 DOM(文檔對(duì)象模型)的值。

數(shù)據(jù)綁定的第一種形式 —— 插值表達(dá)式 —— 展示了模板的 HTML 可以有多豐富。

插值表達(dá)式

在以前的 Angular 教程中,我們遇到過由雙花括號(hào)括起來的插值表達(dá)式,{{和}}。

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

插值表達(dá)式可以把計(jì)算后的字符串插入到 HTML 元素標(biāo)簽內(nèi)的文本或?qū)?biāo)簽的屬性進(jìn)行賦值。

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

在括號(hào)之間的“素材”,通常是組件屬性的名字。Angular 會(huì)用組件中相應(yīng)屬性的字符串值,替換這個(gè)名字。 上例中,Angular 計(jì)算title和heroImageUrl屬性的值,并把它們填在空白處。 首先顯示粗體的應(yīng)用標(biāo)題,然后顯示英雄的圖片。

一般來說,括號(hào)間的素材是一個(gè)模板表達(dá)式,Angular 先對(duì)它求值,再把它轉(zhuǎn)換成字符串。 下列插值表達(dá)式通過把括號(hào)中的兩個(gè)數(shù)字相加說明

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

這個(gè)表達(dá)式可以調(diào)用宿主組件的方法,就像下面用的getVal():

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

Angular 對(duì)所有雙花括號(hào)中的表達(dá)式求值,把求值的結(jié)果轉(zhuǎn)換成字符串,并把它們跟相鄰的字符串字面量連接起來。最后,把這個(gè)組合出來的插值結(jié)果賦給元素或指令的屬性

表面上看,我們?cè)谠貥?biāo)簽之間插入了結(jié)果和對(duì)標(biāo)簽的屬性進(jìn)行了賦值。 這樣思考起來很方便,并且這個(gè)誤解很少給我們帶來麻煩。 但嚴(yán)格來講,這是不對(duì)的。插值表達(dá)式是一個(gè)特殊的語法,Angular 把它轉(zhuǎn)換成了屬性綁定,后面將會(huì)解釋這一點(diǎn)。

講解屬性綁定之前,先深入了解一下模板表達(dá)式和模板語句。

模板表達(dá)式

模板表達(dá)式產(chǎn)生一個(gè)值。 Angular 執(zhí)行這個(gè)表達(dá)式,并把它賦值給綁定目標(biāo)的屬性,這個(gè)綁定目標(biāo)可能是 HTML 元素、組件或指令。

當(dāng)我們寫{{1 + 1}}時(shí),是往插值表達(dá)式的括號(hào)中放進(jìn)了一個(gè)模板表達(dá)式。 在屬性綁定中會(huì)再次看到模板表達(dá)式,它出現(xiàn)在=右側(cè)的引號(hào)中,看起來像這樣:[property]="expression"。

編寫模板表達(dá)式所用的語言看起來很像 JavaScript。 很多 JavaScript 表達(dá)式也是合法的模板表達(dá)式,但不是全部。

JavaScript 中那些具有或可能引發(fā)副作用的表達(dá)式是被禁止的,包括:

  • 賦值 (=,?+=,?-=, ...)

  • new運(yùn)算符

  • 使用;或,的鏈?zhǔn)奖磉_(dá)式

  • 自增或自減操作符 (++和--)

和 JavaScript語 法的其它顯著不同包括:

  • 不支持位運(yùn)算|和&

  • 具有新的模板表達(dá)式運(yùn)算符,比如|和?.

表達(dá)式上下文

也許更讓人吃驚的是,模板表達(dá)式不能引用全局命名空間中的任何東西。 不能引用window或document。不能調(diào)用console.log或Math.max。 它們被局限于只能訪問來自表達(dá)式上下文中的成員。

典型的表達(dá)式上下文就是這個(gè)組件實(shí)例,它是各種綁定值的來源。

當(dāng)看到包裹在雙花括號(hào)中的?title?({{title}}) 時(shí),我們就知道title是這個(gè)數(shù)據(jù)綁定組件中的一個(gè)屬性。 當(dāng)看到[disabled]="isUnchanged"中的?isUnchanged?時(shí),我們就知道正在引用該組件的isUnchanged屬性。

通常,組件本身就是表達(dá)式的上下文,這種情況下,模板表達(dá)式會(huì)引用那個(gè)組件。

表達(dá)式的上下文可以包括組件之外的對(duì)象。?模板引用變量就是備選的上下文對(duì)象之一。

?

表達(dá)式指南

模板表達(dá)式能成就或毀掉一個(gè)應(yīng)用。請(qǐng)遵循下列指南:

  • 沒有可見的副作用

  • 執(zhí)行迅速

  • 非常簡單

  • 冪等性

超出上面指南外的情況應(yīng)該只出現(xiàn)在那些你確信自己已經(jīng)徹底理解的特定場(chǎng)景中。

沒有可見的副作用

模板表達(dá)式除了目標(biāo)屬性的值以外,不應(yīng)該改變應(yīng)用的任何狀態(tài)。

這條規(guī)則是 Angular “單向數(shù)據(jù)流”策略的基礎(chǔ)。 永遠(yuǎn)不用擔(dān)心讀取組件值可能改變另外的顯示值。 在一次單獨(dú)的渲染過程中,視圖應(yīng)該總是穩(wěn)定的。

執(zhí)行迅速

Angular 執(zhí)行模板表達(dá)式比我們想象的頻繁。 它們可能在每一次按鍵或鼠標(biāo)移動(dòng)后被調(diào)用。 表達(dá)式應(yīng)該快速結(jié)束,否則用戶就會(huì)感到拖沓,特別是在較慢的設(shè)備上。 當(dāng)計(jì)算代價(jià)較高時(shí),應(yīng)該考慮緩存那些從其它值計(jì)算得出的值。

非常簡單

雖然可以寫出相當(dāng)復(fù)雜的模板表達(dá)式,但不要那么去寫。

常規(guī)是屬性名或方法調(diào)用。偶爾的邏輯取反 (!) 也還湊合。 其它情況下,應(yīng)在組件中實(shí)現(xiàn)應(yīng)用和業(yè)務(wù)邏輯,使開發(fā)和測(cè)試變得更容易。

冪等性

最好使用冪等的表達(dá)式,因?yàn)樗鼪]有副作用,并且能提升 Angular 變更檢測(cè)的性能。

在 Angular 的術(shù)語中,冪等的表達(dá)式應(yīng)該總是返回完全相同的東西,直到某個(gè)依賴值發(fā)生改變。

在單獨(dú)的一次事件循環(huán)中,被依賴的值不應(yīng)該改變。 如果冪等的表達(dá)式返回一個(gè)字符串或數(shù)字,連續(xù)調(diào)用它兩次,也應(yīng)該返回相同的字符串或數(shù)字。 如果冪等的表達(dá)式返回一個(gè)對(duì)象(包括Date或Array),連續(xù)調(diào)用它兩次,也應(yīng)該返回同一個(gè)對(duì)象的引用。

模板語句

模板語句用來響應(yīng)由綁定目標(biāo)(如 HTML 元素、組件或指令)觸發(fā)的事件

模板語句將在事件綁定一節(jié)看到,它出現(xiàn)在=號(hào)右側(cè)的引號(hào)中,就像這樣:(event)="statement"。

模板語句有副作用。 這正是用戶輸入更新應(yīng)用狀態(tài)的方式。 否則,響應(yīng)事件就沒有什么意義了。

響應(yīng)事件是 Angular 中“單向數(shù)據(jù)流”的另一面。 在一次事件循環(huán)中,可以隨意改變?nèi)魏蔚胤降娜魏螙|西。

和模板表達(dá)式一樣,模板語句使用的語言也像 JavaScript。 模板語句解析器和模板表達(dá)式解析器有所不同,特別之處在于它支持基本賦值 (=) 和表達(dá)式鏈 (;和,)。

然而,某些 JavaScript 語法仍然是不允許的:

  • new運(yùn)算符

  • 自增和自減運(yùn)算符:++和--

  • 操作并賦值,例如+=和-=

  • 位操作符|和&

  • 模板表達(dá)式運(yùn)算符

語句上下文

和表達(dá)式中一樣,語句只能引用語句上下文中 —— 通常是正在綁定事件的那個(gè)組件實(shí)例

模板語句無法引用全局命名空間的任何東西。它們不能引用window或者document, 不能調(diào)用console.log或者M(jìn)ath.max。

(click)="onSave()"中的?onSave?就是數(shù)據(jù)綁定組件實(shí)例中的方法。

語句上下文可以包含組件之外的對(duì)象。?模板引用對(duì)象就是備選上下文對(duì)象之一。 在事件綁定語句中,經(jīng)常會(huì)看到被保留的$event符號(hào),它代表觸發(fā)事件的“消息”或“有效載荷”。

語句指南

和表達(dá)式一樣,避免寫復(fù)雜的模板語句。 常規(guī)是函數(shù)調(diào)用或者屬性賦值。

現(xiàn)在,對(duì)模板表達(dá)式和語句有了一點(diǎn)感覺了吧。 除插值表達(dá)式外,還有各種各樣的數(shù)據(jù)綁定語法,是學(xué)習(xí)它們是時(shí)候了。

?

綁定語法:概覽

數(shù)據(jù)綁定是一種機(jī)制,用來協(xié)調(diào)用戶所見和應(yīng)用數(shù)據(jù)。 雖然我們能往 HTML 推送值或者從 HTML 拉取值, 但如果把這些瑣事交給數(shù)據(jù)綁定框架處理, 應(yīng)用會(huì)更容易編寫、閱讀和維護(hù)。 只要簡單地在綁定源和目標(biāo) HTML 元素之間聲明綁定,框架就會(huì)完成這項(xiàng)工作。

Angular 提供了各種各樣的數(shù)據(jù)綁定,本章將逐一討論。 首先,從高層視角來看看 Angular 數(shù)據(jù)綁定和它的語法。

根據(jù)數(shù)據(jù)流的方向,可以把所有綁定歸為三類。 每一類都有它獨(dú)特的語法:

數(shù)據(jù)方向

語法

綁定類型

單向

從數(shù)據(jù)源

到視圖目標(biāo)

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

插值表達(dá)式

Property

Attribute

樣式

單向

從視圖目標(biāo)

到數(shù)據(jù)源

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

事件

雙向

COPY CODE [(target)] = "expression" bindon-target = "expression"

雙向

譯注:由于 HTML attribute 和 DOM property 在中文中都被翻譯成了“屬性”,無法區(qū)分, 而接下來的部分重點(diǎn)是對(duì)它們進(jìn)行比較。

我們無法改變歷史,因此,在本章的翻譯中,保留了它們的英文形式,不加翻譯,以免混淆。 本章中,如果提到“屬性”的地方,一定是指 property,因?yàn)樵?Angular 中,實(shí)際上很少涉及 attribute。

但在其它章節(jié)中,為簡單起見,凡是能通過上下文明顯區(qū)分開的,就仍統(tǒng)一譯為“屬性”, 區(qū)分不明顯的,會(huì)加注英文。

除了插值表達(dá)式之外的綁定類型,在等號(hào)左邊是目標(biāo)名, 無論是包在括號(hào)中 ([]、()) 還是用前綴形式 (bind-、on-、bindon-) 。

什么是“目標(biāo)”?在回答這個(gè)問題之前,我們必須先挑戰(zhàn)下自我,嘗試用另一種方式來審視模板中的 HTML。

新的思維模型

數(shù)據(jù)綁定的威力和允許用自定義標(biāo)記擴(kuò)展 HTML 詞匯的能力,容易誤導(dǎo)我們把模板 HTML 當(dāng)成?HTML+。

也對(duì),它是?HTML+。 但它也跟我們熟悉的 HTML 有著顯著的不同。 我們需要一種新的思維模型。

在正常的 HTML 開發(fā)過程中,我們使用 HTML 元素創(chuàng)建視覺結(jié)構(gòu), 通過把字符串常量設(shè)置到元素的 attribute 來修改那些元素。

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

在 Angular 模板中,我們?nèi)允褂猛瑯拥姆绞絹韯?chuàng)建結(jié)構(gòu)和初始化 attribute 值。

然后,用封裝了 HTML 的組件創(chuàng)建新元素,并把它們當(dāng)作原生 HTML 元素在模板中使用。

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

這就是HTML+。

現(xiàn)在開始學(xué)習(xí)數(shù)據(jù)綁定。我們碰到的第一種數(shù)據(jù)綁定看起來是這樣的:

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

過會(huì)兒再認(rèn)識(shí)那個(gè)怪異的方括號(hào)記法。直覺告訴我們,我們正在綁定按鈕的disabled?attribute。 并把它設(shè)置為組件的isUnchanged屬性的當(dāng)前值。

但我們的直覺是錯(cuò)的!日常的 HTML 思維模式在誤導(dǎo)我們。 實(shí)際上,一旦開始數(shù)據(jù)綁定,就不再跟 HTML attribute 打交道了。 這里不是設(shè)置 attribute,而是設(shè)置 DOM 元素、組件和指令的 property。

HTML attribute 與 DOM property 的對(duì)比

要想理解 Angular 綁定如何工作,重點(diǎn)是搞清 HTML attribute 和 DOM property 之間的區(qū)別。

attribute 是由 HTML 定義的。property 是由 DOM (Document Object Model) 定義的。

  • 少量 HTML attribute 和 property 之間有著 1:1 的映射,如id。

  • 有些 HTML attribute 沒有對(duì)應(yīng)的 property,如colspan。

  • 有些 DOM property 沒有對(duì)應(yīng)的 attribute,如textContent。

  • 大量 HTML attribute看起來映射到了property…… 但卻不像我們想的那樣!

最后一類尤其讓人困惑…… 除非我們能理解這個(gè)普遍原則:

attribute?初始化?DOM property,然后它們的任務(wù)就完成了。property 的值可以改變;attribute 的值不能改變。

例如,當(dāng)瀏覽器渲染<input type="text" value="Bob">時(shí),它將創(chuàng)建相應(yīng) DOM 節(jié)點(diǎn), 其value?property 被初始化為?“Bob”。

當(dāng)用戶在輸入框中輸入 “Sally” 時(shí),DOM 元素的value?property?變成了 “Sally”。 但是這個(gè) HTML?value?attribute?保持不變。如果我們讀取 input 元素的 attribute,就會(huì)發(fā)現(xiàn)確實(shí)沒變:?input.getAttribute('value') // 返回 "Bob"。

HTML attribute?value指定了初始值;DOM?value?property 是當(dāng)前值。

disabled?attribute 是另一個(gè)古怪的例子。按鈕的disabled?property?是false,因?yàn)槟J(rèn)情況下按鈕是可用的。 當(dāng)我們添加disabledattribute?時(shí),只要它出現(xiàn)了按鈕的disabled?property?就初始化為true,于是按鈕就被禁用了。

添加或刪除disabled?attribute會(huì)禁用或啟用這個(gè)按鈕。但?attribute?的值無關(guān)緊要,這就是我們?yōu)槭裁礇]法通過?<button disabled="false">仍被禁用</button>這種寫法來啟用按鈕。

設(shè)置按鈕的disabled?property(如,通過 Angular 綁定)可以禁用或啟用這個(gè)按鈕。 這就是?property?的價(jià)值。

就算名字相同,HTML attribute 和 DOM property 也不是同一樣?xùn)|西。

這句話很重要,得再強(qiáng)調(diào)一次:

模板綁定是通過?property?和事件來工作的,而不是?attribute。

沒有 ATTRIBUTE 的世界

在 Angular 的世界中,attribute 唯一的作用是用來初始化元素和指令的狀態(tài)。 當(dāng)進(jìn)行數(shù)據(jù)綁定時(shí),只是在與元素和指令的 property 和事件打交道,而 attribute 就完全靠邊站了。

把這個(gè)思維模型牢牢的印在腦子里,接下來,學(xué)習(xí)什么是綁定目標(biāo)。

綁定目標(biāo)

數(shù)據(jù)綁定的目標(biāo)是 DOM 中的某些東西。 這個(gè)目標(biāo)可能是(元素 | 組件 | 指令的)property、(元素 | 組件 | 指令的)事件,或(極少數(shù)情況下) attribute 名。 下面是的匯總表:

綁定類型

目標(biāo)

范例

Property

元素的 property

組件的 property

指令的 property

COPY CODE <img [src] = "heroImageUrl"> <hero-detail [hero]="currentHero"></hero-detail> <div [ngClass] = "{selected: isSelected}"></div>

事件

元素的事件

組件的事件

指令的事件

COPY CODE <button (click) = "onSave()">Save</button> <hero-detail (deleteRequest)="deleteHero()"></hero-detail> <div (myClick)="clicked=$event">click me</div>

雙向

事件與 property

COPY CODE <input [(ngModel)]="heroName">
Attribute

attribute(例外情況)

COPY CODE <button [attr.aria-label]="help">help</button>

CSS 類

class?property

COPY CODE <div [class.special]="isSpecial">Special</div>

樣式

style?property

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

讓我們從結(jié)構(gòu)性云層中走出來,看看每種綁定類型的具體情況。

屬性 (property) 綁定

當(dāng)要把視圖元素的屬性 (property) 設(shè)置為模板表達(dá)式時(shí),就要寫模板的屬性 (property) 綁定

最常用的屬性綁定是把元素屬性設(shè)置為組件屬性的值。 下面這個(gè)例子中,image 元素的src屬性會(huì)被綁定到組件的heroImageUrl屬性上:

<img [src]="heroImageUrl">

另一個(gè)例子是當(dāng)組件說它isUnchanged(未改變)時(shí)禁用按鈕:

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

另一個(gè)例子是設(shè)置指令的屬性:

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

還有另一個(gè)例子是設(shè)置自定義組件的模型屬性(這是父子組件之間通訊的重要途徑):

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

單向輸入

人們經(jīng)常把屬性綁定描述成單向數(shù)據(jù)綁定,因?yàn)橹档牧鲃?dòng)是單向的,從組件的數(shù)據(jù)屬性流動(dòng)到目標(biāo)元素的屬性。

不能使用屬性綁定來從目標(biāo)元素拉取值,也不能綁定到目標(biāo)元素的屬性來讀取它。只能設(shè)置它。

也不能使用屬性 綁定 來調(diào)用目標(biāo)元素上的方法。

如果這個(gè)元素觸發(fā)了事件,可以通過事件綁定來監(jiān)聽它們。

如果必須讀取目標(biāo)元素上的屬性或調(diào)用它的某個(gè)方法,得用另一種技術(shù)。 參見 API 參考手冊(cè)中的?ViewChild?和?ContentChild。

綁定目標(biāo)

包裹在方括號(hào)中的元素屬性名標(biāo)記著目標(biāo)屬性。下列代碼中的目標(biāo)屬性是 image 元素的src屬性。

<img [src]="heroImageUrl">

有些人喜歡用bind-前綴的可選形式,并稱之為規(guī)范形式:

<img bind-src="heroImageUrl">

目標(biāo)的名字總是 property 的名字。即使它看起來和別的名字一樣。 看到src時(shí),可能會(huì)把它當(dāng)做 attribute。不!它不是!它是 image 元素的 property 名。

元素屬性可能是最常見的綁定目標(biāo),但 Angular 會(huì)先去看這個(gè)名字是否是某個(gè)已知指令的屬性名,就像下面的例子中一樣:

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

嚴(yán)格來說,Angular 正在匹配指令的輸入屬性的名字。 這個(gè)名字是指令的inputs數(shù)組中所列的名字,或者是帶有@Input()裝飾器的屬性。 這些輸入屬性被映射為指令自己的屬性。

如果名字沒有匹配上已知指令或元素的屬性,Angular 就會(huì)報(bào)告“未知指令”的錯(cuò)誤。

返回恰當(dāng)?shù)念愋?/h3>

模板表達(dá)式應(yīng)該返回目標(biāo)屬性所需類型的值。 如果目標(biāo)屬性想要個(gè)字符串,就返回字符串。 如果目標(biāo)屬性想要個(gè)數(shù)字,就返回?cái)?shù)字。 如果目標(biāo)屬性想要個(gè)對(duì)象,就返回對(duì)象。

HeroDetail組件的hero屬性想要一個(gè)Hero對(duì)象,那就在屬性綁定中精確地給它一個(gè)Hero對(duì)象:

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

別忘了方括號(hào)

方括號(hào)告訴 Angular 要計(jì)算模板表達(dá)式。 如果忘了加方括號(hào),Angular 會(huì)把這個(gè)表達(dá)式當(dāng)做字符串常量看待,并用該字符串來初始化目標(biāo)屬性。 它不會(huì)計(jì)算這個(gè)字符串。

不要出現(xiàn)這樣的失誤:

<!-- ERROR: HeroDetailComponent.hero expects aHero object, not the string "currentHero" --><hero-detail hero="currentHero"></hero-detail>

一次性字符串初始化

當(dāng)下列條件滿足時(shí),應(yīng)該省略括號(hào):

  • 目標(biāo)屬性接受字符串值。

  • 字符串是個(gè)固定值,可以直接合并到模塊中。

  • 這個(gè)初始值永不改變。

我們經(jīng)常這樣在標(biāo)準(zhǔn) HTML 中用這種方式初始化 attribute,這種方式也可以用在初始化指令和組件的屬性。 下面這個(gè)例子把HeroDetailComponent的prefix屬性初始化為固定的字符串,而不是模板表達(dá)式。Angular 設(shè)置它,然后忘記它。

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

作為對(duì)比,[hero]綁定是組件的currentHero屬性的活綁定,它會(huì)一直隨著更新。

屬性綁定還是插值表達(dá)式?

我們通常得在插值表達(dá)式和屬性綁定之間做出選擇。 下列這幾對(duì)綁定做的事情完全相同:

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

在多數(shù)情況下,插值表達(dá)式是更方便的備選項(xiàng)。 實(shí)際上,在渲染視圖之前,Angular 把這些插值表達(dá)式翻譯成相應(yīng)的屬性綁定。

當(dāng)要渲染的數(shù)據(jù)類型是字符串時(shí),沒有技術(shù)上的理由證明哪種形式更好。 我們傾向于可讀性,所以傾向于插值表達(dá)式。 建議建立代碼風(fēng)格規(guī)則,選擇一種形式, 這樣,既遵循了規(guī)則,又能讓手頭的任務(wù)做起來更自然。

但數(shù)據(jù)類型不是字符串時(shí),就必須使用屬性綁定了。

內(nèi)容安全

假設(shè)下面的惡毒內(nèi)容

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

幸運(yùn)的是,Angular 數(shù)據(jù)綁定對(duì)危險(xiǎn) HTML 有防備。 在顯示它們之前,它對(duì)內(nèi)容先進(jìn)行消毒。 不管是插值表達(dá)式還是屬性綁定,都不會(huì)允許帶有 script 標(biāo)簽的 HTML 泄漏到瀏覽器中。

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

插值表達(dá)式處理 script 標(biāo)簽與屬性綁定有所不同,但是二者都只渲染沒有危害的內(nèi)容。

?

attribute、class 和 style 綁定

模板語法為那些不太適合使用屬性綁定的場(chǎng)景提供了專門的單向數(shù)據(jù)綁定形式。

attribute 綁定

可以通過attribute 綁定來直接設(shè)置 attribute 的值。

這是“綁定到目標(biāo)屬性 (property)”這條規(guī)則中唯一的例外。這是唯一的能創(chuàng)建和設(shè)置 attribute 的綁定形式。

本章中,通篇都在說通過屬性綁定來設(shè)置元素的屬性總是好于用字符串設(shè)置 attribute。為什么 Angular 還提供了 attribute 綁定呢?

因?yàn)楫?dāng)元素沒有屬性可綁的時(shí)候,就必須使用 attribute 綁定。

考慮?ARIA,?SVG?和 table 中的 colspan/rowspan 等 attribute。 它們是純粹的 attribute,沒有對(duì)應(yīng)的屬性可供綁定。

如果想寫出類似下面這樣的東西,現(xiàn)狀會(huì)令我們痛苦:

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

會(huì)得到這個(gè)錯(cuò)誤:

Template parse errors: Can't bind to 'colspan' since it isn't a known native property模板解析錯(cuò)誤:不能綁定到 'colspan',因?yàn)樗皇且阎脑鷮傩?

正如提示中所說,<td>元素沒有colspan屬性。 但是插值表達(dá)式和屬性綁定只能設(shè)置屬性,不能設(shè)置 attribute。

我們需要 attribute 綁定來創(chuàng)建和綁定到這樣的 attribute。

attribute 綁定的語法與屬性綁定類似。 但方括號(hào)中的部分不是元素的屬性名,而是由attr前綴,一個(gè)點(diǎn) (.) 和 attribute 的名字組成。 可以通過值為字符串的表達(dá)式來設(shè)置 attribute 的值。

這里把[attr.colspan]綁定到一個(gè)計(jì)算值:

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

這里是表格渲染出來的樣子:

One-Two
FiveSix

attribute 綁定的主要用例之一是設(shè)置 ARIA attribute(譯注:ARIA指可訪問性,用于給殘障人士訪問互聯(lián)網(wǎng)提供便利), 就像這個(gè)例子中一樣:

<!-- create and set an aria attribute for assistive technology --> <button [attr.aria-label]="actionName">{{actionName}} with Aria</button>

CSS 類綁定

借助?CSS 類綁定,可以從元素的class?attribute 上添加和移除 CSS 類名。

CSS 類綁定綁定的語法與屬性綁定類似。 但方括號(hào)中的部分不是元素的屬性名,而是由class前綴,一個(gè)點(diǎn) (.)和 CSS 類的名字組成, 其中后兩部分是可選的。形如:[class.class-name]。

下列例子示范了如何通過 CSS 類綁定來添加和移除應(yīng)用的 "special" 類。不用綁定直接設(shè)置 attribute 時(shí)是這樣的:

<!-- standard class attribute setting --> <div class="bad curly special">Bad curly special</div>

可以把它改寫為綁定到所需 CSS 類名的綁定;這是一個(gè)或者全有或者全無的替換型綁定。 (譯注:即當(dāng) badCurly 有值時(shí) class 這個(gè) attribute 設(shè)置的內(nèi)容會(huì)被完全覆蓋)

<!-- reset/override all class names with a binding --> <div class="bad curly special" [class]="badCurly">Bad curly</div>

最后,可以綁定到特定的類名。 當(dāng)模板表達(dá)式的求值結(jié)果是真值時(shí),Angular 會(huì)添加這個(gè)類,反之則移除它。

<!-- toggle the "special" class on/off with a property --> <div [class.special]="isSpecial">The class binding is special</div> <!-- binding to `class.special` trumps the class attribute --> <div class="special" [class.special]="!isSpecial">This one is not so special</div>

雖然這是切換單一類名的好辦法,但我們通常更喜歡使用?NgClass指令?來同時(shí)管理多個(gè)類名。

樣式綁定

通過樣式綁定,可以設(shè)置內(nèi)聯(lián)樣式。

樣式綁定的語法與屬性綁定類似。 但方括號(hào)中的部分不是元素的屬性名,而由style前綴,一個(gè)點(diǎn) (.)和 CSS 樣式的屬性名組成。 形如:[style.style-property]。

<button [style.color] = "isSpecial ? 'red': 'green'">Red</button> <button [style.background-color]="canSave ? 'cyan': 'grey'" >Save</button>

有些樣式綁定中的樣式帶有單位。在這里,以根據(jù)條件用 “em” 和 “%” 來設(shè)置字體大小的單位。

<button [style.font-size.em]="isSpecial ? 3 : 1" >Big</button> <button [style.font-size.%]="!isSpecial ? 150 : 50" >Small</button>

雖然這是設(shè)置單一樣式的好辦法,但我們通常更喜歡使用?NgStyle指令?來同時(shí)設(shè)置多個(gè)內(nèi)聯(lián)樣式。

注意,樣式屬性命名方法可以用中線命名法,像上面的一樣 也可以用駝峰式命名法,如fontSize。

事件綁定

前面遇到的綁定的數(shù)據(jù)流都是單向的:從組件到元素

用戶不會(huì)只盯著屏幕看。它們會(huì)在輸入框中輸入文本。它們會(huì)從列表中選取條目。 它們會(huì)點(diǎn)擊按鈕。這類用戶動(dòng)作可能導(dǎo)致反向的數(shù)據(jù)流:從元素到組件。

知道用戶動(dòng)作的唯一方式是監(jiān)聽某些事件,如按鍵、鼠標(biāo)移動(dòng)、點(diǎn)擊和觸摸屏幕。 可以通過 Angular 事件綁定來聲明對(duì)哪些用戶動(dòng)作感興趣。

事件綁定語法由等號(hào)左側(cè)帶圓括號(hào)的目標(biāo)事件和右側(cè)引號(hào)中的模板語句組成。 下面事件綁定監(jiān)聽按鈕的點(diǎn)擊事件。每當(dāng)點(diǎn)擊發(fā)生時(shí),都會(huì)調(diào)用組件的onSave()方法。

<button (click)="onSave()">Save</button>

目標(biāo)事件

圓括號(hào)中的名稱?—— 比如(click)?—— 標(biāo)記出目標(biāo)事件。在下面例子中,目標(biāo)是按鈕的 click 事件。

<button (click)="onSave()">Save</button>

有些人更喜歡帶on-前綴的備選形式,稱之為規(guī)范形式

<button on-click="onSave()">On Save</button>

元素事件可能是更常見的目標(biāo),但 Angular 會(huì)先看這個(gè)名字是否能匹配上已知指令的事件屬性,就像下面這個(gè)例子:

<!-- `myClick` is an event on the custom `ClickDirective` --> <div (myClick)="clickMessage=$event">click with myClick</div>

更多關(guān)于該myClick指令的解釋,見給輸入/輸出屬性起別名。

如果這個(gè)名字沒能匹配到元素事件或已知指令的輸出屬性,Angular 就會(huì)報(bào)“未知指令”錯(cuò)誤。

$event?和事件處理語句

在事件綁定中,Angular 會(huì)為目標(biāo)事件設(shè)置事件處理器。

當(dāng)事件發(fā)生時(shí),這個(gè)處理器會(huì)執(zhí)行模板語句。 典型的模板語句通常涉及到響應(yīng)事件執(zhí)行動(dòng)作的接收器,例如從 HTML 控件中取得值,并存入模型。

綁定會(huì)通過名叫$event的事件對(duì)象傳遞關(guān)于此事件的信息(包括數(shù)據(jù)值)。

事件對(duì)象的形態(tài)取決于目標(biāo)事件。如果目標(biāo)事件是原生 DOM 元素事件,?$event就是?DOM事件對(duì)象,它有像target和target.value這樣的屬性。

考慮這個(gè)范例:

<input [value]="currentHero.firstName" (input)="currentHero.firstName=$event.target.value" >

上面的代碼在把輸入框的value屬性綁定到firstName屬性。 要監(jiān)聽對(duì)值的修改,代碼綁定到輸入框的input事件。 當(dāng)用戶造成更改時(shí),input事件被觸發(fā),并在包含了 DOM 事件對(duì)象 ($event) 的上下文中執(zhí)行這條語句。

要更新firstName屬性,就要通過路徑$event.target.value來獲取更改后的值。

如果事件屬于指令(回想一下,組件是指令的一種),那么$event具體是什么由指令決定。

?

使用?EventEmitter?實(shí)現(xiàn)自定義事件

通常,指令使用 Angular?EventEmitter?來觸發(fā)自定義事件。 指令創(chuàng)建一個(gè)EventEmitter實(shí)例,并且把它作為屬性暴露出來。 指令調(diào)用EventEmitter.emit(payload)來觸發(fā)事件,可以傳入任何東西作為消息載荷。 父指令通過綁定到這個(gè)屬性來監(jiān)聽事件,并通過$event對(duì)象來訪問載荷。

假設(shè)HeroDetailComponent用于顯示英雄的信息,并響應(yīng)用戶的動(dòng)作。 雖然HeroDetailComponent包含刪除按鈕,但它自己并不知道該如何刪除這個(gè)英雄。 最好的做法是觸發(fā)事件來報(bào)告“刪除用戶”的請(qǐng)求。

下面的代碼節(jié)選自HeroDetailComponent:

src/app/hero-detail.component.ts (template)

template: ` <div><img src="{{heroImageUrl}}"><span [style.text-decoration]="lineThrough">{{prefix}} {{hero?.fullName}}</span><button (click)="delete()">Delete</button> </div>`

src/app/hero-detail.component.ts (deleteRequest)

// This component make a request but it can't actually delete a hero. deleteRequest = new EventEmitter<Hero>(); delete() { this.deleteRequest.emit(this.hero); }

組件定義了deleteRequest屬性,它是EventEmitter實(shí)例。 當(dāng)用戶點(diǎn)擊刪除時(shí),組件會(huì)調(diào)用delete()方法,讓EventEmitter發(fā)出一個(gè)Hero對(duì)象。

現(xiàn)在,假設(shè)有個(gè)宿主的父組件,它綁定了HeroDetailComponent的deleteRequest事件。

<hero-detail (deleteRequest)="deleteHero($event)" [hero]="currentHero"></hero-detail>

當(dāng)deleteRequest事件觸發(fā)時(shí),Angular 調(diào)用父組件的deleteHero方法, 在$event變量中傳入要?jiǎng)h除的英雄(來自HeroDetail)。

模板語句有副作用

deleteHero方法有副作用:它刪除了一個(gè)英雄。 模板語句的副作用不僅沒問題,反而正是所期望的。

刪除這個(gè)英雄會(huì)更新模型,還可能觸發(fā)其它修改,包括向遠(yuǎn)端服務(wù)器的查詢和保存。 這些變更通過系統(tǒng)進(jìn)行擴(kuò)散,并最終顯示到當(dāng)前以及其它視圖中。

雙向數(shù)據(jù)綁定

我們經(jīng)常需要顯示數(shù)據(jù)屬性,并在用戶作出更改時(shí)更新該屬性。

在元素層面上,既要設(shè)置元素屬性,又要監(jiān)聽元素事件變化。

Angular 為此提供一種特殊的雙向數(shù)據(jù)綁定語法:[(x)]。?[(x)]語法結(jié)合了屬性綁定的方括號(hào)[x]和事件綁定的圓括號(hào)(x)。

[( )] = 盒子里的香蕉

想象盒子里的香蕉來記住方括號(hào)套圓括號(hào)。

當(dāng)一個(gè)元素?fù)碛锌梢栽O(shè)置的屬性x和對(duì)應(yīng)的事件xChange時(shí),解釋[(x)]語法就容易多了。 下面的SizerComponent符合這個(gè)模式。它有size屬性和伴隨的sizeChange事件:

src/app/sizer.component.ts

  • import { Component, EventEmitter, Input, Output } from '@angular/core';
  • @Component({
  • selector: 'my-sizer',
  • template: `
  • <div>
  • <button (click)="dec()" title="smaller">-</button>
  • <button (click)="inc()" title="bigger">+</button>
  • <label [style.font-size.px]="size">FontSize: {{size}}px</label>
  • </div>`
  • })
  • export class SizerComponent {
  • @Input() size: number | string;
  • @Output() sizeChange = new EventEmitter<number>();
  • dec() { this.resize(-1); }
  • inc() { this.resize(+1); }
  • resize(delta: number) {
  • this.size = Math.min(40, Math.max(8, +this.size + delta));
  • this.sizeChange.emit(this.size);
  • }
  • }
  • size的初始值是一個(gè)輸入值,來自屬性綁定。(譯注:注意size前面的@Input) 點(diǎn)擊按鈕,在最小/最大值范圍限制內(nèi)增加或者減少size。 然后用調(diào)整后的size觸發(fā)sizeChange事件。

    下面的例子中,AppComponent.fontSize被雙向綁定到SizerComponent:

    <my-sizer [(size)]="fontSizePx"></my-sizer> <div [style.font-size.px]="fontSizePx">Resizable Text</div>

    SizerComponent.size初始值是AppComponent.fontSizePx。 點(diǎn)擊按鈕時(shí),通過雙向綁定更新AppComponent.fontSizePx。 被修改的AppComponent.fontSizePx通過樣式綁定,改變文本的顯示大小。 試一下在線例子。

    雙向綁定語法實(shí)際上是屬性綁定和事件綁定的語法糖。 Angular將SizerComponent的綁定分解成這樣:

    <my-sizer [size]="fontSizePx" (sizeChange)="fontSizePx=$event"></my-sizer>

    $event變量包含了SizerComponent.sizeChange事件的荷載。 當(dāng)用戶點(diǎn)擊按鈕時(shí),Angular 將$event賦值給AppComponent.fontSizePx。

    很清楚,比起單獨(dú)綁定屬性和事件,雙向數(shù)據(jù)綁定語法顯得非常方便。

    我們希望能在像<input>和<select>這樣的 HTML 元素上使用雙向數(shù)據(jù)綁定。 可惜,原生 HTML 元素不遵循x值和xChange事件的模式。

    幸運(yùn)的是,Angular 以?NgModel?指令為橋梁,允許在表單元素上使用雙向數(shù)據(jù)綁定。

    使用 NgModel 進(jìn)行雙向數(shù)據(jù)綁定

    當(dāng)開發(fā)數(shù)據(jù)輸入表單時(shí),我們經(jīng)常希望能顯示數(shù)據(jù)屬性,并在用戶做出變更時(shí)更新該屬性。

    使用NgModel指令進(jìn)行雙向數(shù)據(jù)綁定讓它變得更加容易。請(qǐng)看下例:

    <input [(ngModel)]="currentHero.firstName"> 要使用 NGMODEL,必須導(dǎo)入 FORMSMODULE

    在使用ngModel做雙向數(shù)據(jù)綁定之前,得先導(dǎo)入FormsModule, 把它加入 Angular 模塊的imports列表。 學(xué)習(xí)關(guān)于FormsModule和ngModel的更多知識(shí),參見表單。

    下面展示了如何導(dǎo)入FormsModule,讓[(ngModel)]變得可用:

    src/app/app.module.ts (FormsModule import)

    import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { FormsModule } from '@angular/forms'; import { AppComponent } from './app.component'; @NgModule({ imports: [ BrowserModule, FormsModule ], declarations: [ AppComponent ], bootstrap: [ AppComponent ] }) export class AppModule { }

    [(ngModel)]內(nèi)幕

    回顧一下firstName的綁定,值得注意的是,可以通過分別綁定<input>元素的value屬性和`input事件來實(shí)現(xiàn)同樣的效果。

    <input [value]="currentHero.firstName" (input)="currentHero.firstName=$event.target.value" >

    這樣很笨拙。誰能記住哪個(gè)元素屬性用于設(shè)置,哪個(gè)用于發(fā)出用戶更改? 如何從輸入框中提取出當(dāng)前顯示的文本,以便更新數(shù)據(jù)屬性? 誰想每次都去查一遍?

    ngModel指令通過它自己的ngModel輸入屬性和ngModelChange輸出屬性隱藏了這些繁瑣的細(xì)節(jié)。

    <input[ngModel]="currentHero.firstName" (ngModelChange)="currentHero.firstName=$event">

    ngModel數(shù)據(jù)屬性設(shè)置元素的 value 屬性,ngModelChange事件屬性監(jiān)聽元素 value 的變化。

    每種元素的特點(diǎn)各不相同,所以NgModel指令只能在一些特定表單元素上使用,例如輸入文本框,因?yàn)樗鼈冎С?ControlValueAccessor。

    除非寫一個(gè)合適的值訪問器,否則不能把[(ngModel)]用在自定義組件上。 但值訪問器技術(shù)超出了本章的范圍。 對(duì)于不能控制其 API 的 Angular 組件或者 Web 組件,可能需要為其添加?value accessor。

    但是對(duì)于我們能控制的 Angular 組件來說,這么做就完全沒有必要了。 因?yàn)榭梢灾付ㄖ岛褪录傩悦謥磉M(jìn)行基本的 Angular?雙向綁定語法,完全不用NgModel。

    獨(dú)立的ngModel綁定相比直接綁定元素的原生屬性是個(gè)改進(jìn),但還能做得更好。

    我們不應(yīng)該提及數(shù)據(jù)屬性兩次。Angular 應(yīng)該能捕捉組件的數(shù)據(jù)屬性,并用一條聲明來設(shè)置它——依靠[(ngModel)],可以這么做:

    <input [(ngModel)]="currentHero.firstName">

    [(ngModel)]就是我們所需的一切嗎?有沒有什么理由需要回退到它的展開形式?

    [(ngModel)]語法只能設(shè)置一個(gè)數(shù)據(jù)綁定屬性。 如果需要做更多或不同的事情,就得自己用它的展開形式。

    來做點(diǎn)淘氣的事吧,比如強(qiáng)制讓輸入值變成大寫形式:

    <input[ngModel]="currentHero.firstName" (ngModelChange)="setUpperCaseFirstName($event)">

    下面是實(shí)際操作中的所有變體形式,包括這個(gè)大寫版本:

    ?

    內(nèi)置指令

    上一版本的 Angular 中包含了超過 70 個(gè)內(nèi)置指令。 社區(qū)貢獻(xiàn)了更多,這還沒算為內(nèi)部應(yīng)用而創(chuàng)建的無數(shù)私有指令。

    在新版的 Angular 中不需要那么多指令。 使用更強(qiáng)大、更富有表現(xiàn)力的 Angular 綁定系統(tǒng),其實(shí)可以達(dá)到同樣的效果。 如果能用簡單的綁定達(dá)到目的,為什么還要?jiǎng)?chuàng)建指令來處理點(diǎn)擊事件呢?

    <button (click)="onSave()">Save</button>

    我們?nèi)匀豢梢詮暮喕瘡?fù)雜任務(wù)的指令中獲益。 Angular 發(fā)布時(shí)仍然帶有內(nèi)置指令,只是沒那么多了。 我們?nèi)詴?huì)寫自己的指令,只是沒那么多了。

    下面來看一下那些最常用的內(nèi)置指令。

    NgClass

    我們經(jīng)常用動(dòng)態(tài)添加或刪除 CSS 類的方式來控制元素如何顯示。 通過綁定到NgClass,可以同時(shí)添加或移除多個(gè)類。

    CSS 類綁定?是添加或刪除單個(gè)類的最佳途徑。

    <!-- toggle the "special" class on/off with a property --> <div [class.special]="isSpecial">The class binding is special</div>

    當(dāng)想要同時(shí)添加或移除多個(gè)?CSS 類時(shí),NgClass指令可能是更好的選擇。

    綁定到一個(gè) key:value 形式的控制對(duì)象,是應(yīng)用NgClass的好方式。這個(gè)對(duì)象中的每個(gè) key 都是一個(gè) CSS 類名,如果它的 value 是true,這個(gè)類就會(huì)被加上,否則就會(huì)被移除。

    下面的組件方法setClasses管理了三個(gè) CSS 類的狀態(tài):

    currentClasses: {}; setCurrentClasses() { // CSS classes: added/removed per current state of component properties this.currentClasses = { saveable: this.canSave, modified: !this.isUnchanged, special: this.isSpecial }; }

    把NgClass屬性綁定到currentClasses,根據(jù)它來設(shè)置此元素的CSS類:

    <div [ngClass]="currentClasses">This div is initially saveable, unchanged, and special</div>

    你既可以在初始化時(shí)調(diào)用setCurrentClassess(),也可以在所依賴的屬性變化時(shí)調(diào)用。

    NgStyle

    我們可以根據(jù)組件的狀態(tài)動(dòng)態(tài)設(shè)置內(nèi)聯(lián)樣式。?NgStyle綁定可以同時(shí)設(shè)置多個(gè)內(nèi)聯(lián)樣式。

    樣式綁定是設(shè)置單一樣式值的簡單方式。

    <div [style.font-size]="isSpecial ? 'x-large' : 'smaller'" > This div is x-large. </div>

    如果要同時(shí)設(shè)置多個(gè)內(nèi)聯(lián)樣式,NgStyle指令可能是更好的選擇。

    NgStyle需要綁定到一個(gè) key:value 控制對(duì)象。 對(duì)象的每個(gè) key 是樣式名,它的 value 是能用于這個(gè)樣式的任何值。

    來看看組件的setCurrentStyles方法,它會(huì)根據(jù)另外三個(gè)屬性的狀態(tài)把組件的currentStyles屬性設(shè)置為一個(gè)定義了三個(gè)樣式的對(duì)象:

    currentStyles: {}; setCurrentStyles() { this.currentStyles = { // CSS styles: set per current state of component properties 'font-style': this.canSave ? 'italic' : 'normal', 'font-weight': !this.isUnchanged ? 'bold' : 'normal', 'font-size': this.isSpecial ? '24px' : '12px' }; }

    把NgStyle屬性綁定到currentStyles,以據(jù)此設(shè)置此元素的樣式:

    <div [ngStyle]="currentStyles"> This div is initially italic, normal weight, and extra large (24px). </div>

    你既可以在初始化時(shí)調(diào)用setCurrentStyles(),也可以在所依賴的屬性變化時(shí)調(diào)用。

    NgIf

    通過綁定NgIf指令到真值表達(dá)式,可以把元素子樹(元素及其子元素)添加到 DOM 上。

    <div *ngIf="currentHero">Hello, {{currentHero.firstName}}</div>

    別忘了ngIf前面的星號(hào)(*)。 更多信息,見?* 與 <template>。

    綁定到假值表達(dá)式將從 DOM 中移除元素子樹。

    <!-- because of the ngIf guard`nullHero.firstName` never has a chance to fail --> <div *ngIf="nullHero">Hello, {{nullHero.firstName}}</div> <!-- Hero Detail is not in the DOM because isActive is false--> <hero-detail *ngIf="isActive"></hero-detail>

    可見性和NGIF不是一回事

    我們可以通過類綁定或樣式綁定來顯示和隱藏元素子樹(元素及其子元素)。

    <!-- isSpecial is true --> <div [class.hidden]="!isSpecial">Show with class</div> <div [class.hidden]="isSpecial">Hide with class</div> <!-- HeroDetail is in the DOM but hidden --> <hero-detail [class.hidden]="isSpecial"></hero-detail> <div [style.display]="isSpecial ? 'block' : 'none'">Show with style</div> <div [style.display]="isSpecial ? 'none' : 'block'">Hide with style</div>

    隱藏子樹和用NgIf排除子樹是截然不同的。

    當(dāng)隱藏子樹時(shí),它仍然留在 DOM 中。 子樹中的組件及其狀態(tài)仍然保留著。 即使對(duì)于不可見屬性,Angular 也會(huì)繼續(xù)檢查變更。 子樹可能占用相當(dāng)可觀的內(nèi)存和運(yùn)算資源。

    當(dāng)NgIf為false時(shí),Angular 從 DOM 中物理地移除了這個(gè)元素子樹。 它銷毀了子樹中的組件及其狀態(tài),也潛在釋放了可觀的資源,最終讓用戶體驗(yàn)到更好的性能。

    顯示 / 隱藏技術(shù)用在小型元素樹上可能還不錯(cuò)。 但在隱藏大樹時(shí)我們得小心;NgIf可能是更安全的選擇。但要記住:永遠(yuǎn)得先測(cè)量,再下結(jié)論。

    NgSwitch

    當(dāng)需要從一組可能的元素樹中根據(jù)條件顯示一個(gè)時(shí),我們就把它綁定到NgSwitch。 Angular 將只把選中的元素樹放進(jìn) DOM 中。

    下面是例子:

    <span [ngSwitch]="toeChoice"> <span *ngSwitchCase="'Eenie'">Eenie</span> <span *ngSwitchCase="'Meanie'">Meanie</span> <span *ngSwitchCase="'Miney'">Miney</span> <span *ngSwitchCase="'Moe'">Moe</span> <span *ngSwitchDefault>other</span> </span>

    我們把作為父指令的NgSwitch綁定到能返回開關(guān)值的表達(dá)式。 本例中,這個(gè)值是字符串,但它也可以是任何類型的值。

    這個(gè)例子中,父指令NgSwitch控制一組<span>子元素。 每個(gè)<span>或者掛在匹配值表達(dá)式上,或者被標(biāo)記為默認(rèn)情況。

    任何時(shí)候,這些?span?中最多只有一個(gè)會(huì)出現(xiàn)在 DOM 中。

    如果這個(gè)?span?的匹配值等于開關(guān)值,Angular 就把這個(gè)<span>添加到 DOM 中。 如果沒有任何?span?匹配上,Angular 就把默認(rèn)的?span?添加到 DOM 中。 Angular 會(huì)移除并銷毀所有其它的?span。

    可以用任何其它元素代替本例中的?span。 那個(gè)元素可以是帶有巨大子樹的<div>。 只有匹配的<div>和它的子樹會(huì)顯示在 DOM 中,其它的則會(huì)被移除。

    這里有三個(gè)相互合作的指令:

  • ngSwitch:綁定到返回開關(guān)值的表達(dá)式

  • ngSwitchCase:綁定到返回匹配值的表達(dá)式

  • ngSwitchDefault:用于標(biāo)記出默認(rèn)元素的 attribute

  • 不要在ngSwitch的前面加星號(hào) (*),而應(yīng)該用屬性綁定。

    把星號(hào) (*) 放在ngSwitchCase和ngSwitchDefault的前面。 要了解更多信息,見?* 與 <template>。

    NgFor

    NgFor是一個(gè)重復(fù)器指令 —— 自定義數(shù)據(jù)顯示的一種方式。

    我們的目標(biāo)是展示一個(gè)由多個(gè)條目組成的列表。首先定義了一個(gè) HTML 塊,它規(guī)定了單個(gè)條目應(yīng)該如何顯示。 再告訴 Angular 把這個(gè)塊當(dāng)做模板,渲染列表中的每個(gè)條目。

    下例中,NgFor應(yīng)用在一個(gè)簡單的<div>上:

    <div *ngFor="let hero of heroes">{{hero.fullName}}</div>

    也可以把NgFor應(yīng)用在一個(gè)組件元素上,就下例這樣:

    <hero-detail *ngFor="let hero of heroes" [hero]="hero"></hero-detail>

    不要忘了ngFor前面的星號(hào) (*)。 更多信息,見?* 與 <template>

    賦值給*ngFor的文本是用于指導(dǎo)重復(fù)器如何工作的指令。

    NGFOR 微語法

    賦值給*ngFor的字符串不是模板表達(dá)式。 它是一個(gè)微語法?—— 由 Angular 自己解釋的小型語言。在這個(gè)例子中,字符串"let hero of heroes"的含義是:

    取出heroes數(shù)組中的每個(gè)英雄,把它存入局部變量hero中,并在每次迭代時(shí)對(duì)模板 HTML 可用

    Angular 把這個(gè)指令翻譯成一組元素和綁定。

    在前面的兩個(gè)例子中,ngFor指令在heroes數(shù)組上進(jìn)行迭代(它是由父組件的heroes屬性返回的), 以其所在的元素為模板“沖壓”出很多實(shí)例。 Angular 為數(shù)組中的每個(gè)英雄創(chuàng)建了此模板的一個(gè)全新實(shí)例。

    hero前面的let關(guān)鍵字創(chuàng)建了名叫hero的模板輸入變量。

    模板輸入變量和模板引用變量不是一回事!

    在模板中使用這個(gè)變量來訪問英雄的屬性,就像在插值表達(dá)式中所做的那樣。 也可以把這個(gè)變量傳給組件元素上的綁定,就像對(duì)hero-detail所做的那樣。

    帶索引的 NGFOR

    ngFor指令支持可選的index,它在迭代過程中會(huì)從 0 增長到“數(shù)組的長度”。 可以通過模板輸入變量來捕獲這個(gè) index,并在模板中使用。

    下例把 index 捕獲到名叫i的變量中,使用它“沖壓出”像 "1 - Hercules Son of Zeus" 這樣的條目。

    <div *ngFor="let hero of heroes; let i=index">{{i + 1}} - {{hero.fullName}}</div>

    要學(xué)習(xí)更多的類似 index?的值,例如last、even和odd,請(qǐng)參閱?NgFor API 參考。

    NGFORTRACKBY

    ngFor指令有時(shí)候會(huì)性能較差,特別是在大型列表中。 對(duì)一個(gè)條目的一丁點(diǎn)改動(dòng)、移除或添加,都會(huì)導(dǎo)致級(jí)聯(lián)的 DOM 操作。

    例如,我們可以通過重新從服務(wù)器查詢來刷新英雄列表。 刷新后的列表可能包含很多(如果不是全部的話)以前顯示過的英雄。

    我們知道這一點(diǎn),是因?yàn)槊總€(gè)英雄的id沒有變化。 但在 Angular 看來,它只是一個(gè)由新的對(duì)象引用構(gòu)成的新列表, 它沒有選擇,只能清理舊列表、舍棄那些 DOM 元素,并且用新的 DOM 元素來重建一個(gè)新列表。

    如果給它一個(gè)追蹤函數(shù),Angular 就可以避免這種折騰。 追蹤函數(shù)告訴 Angular:我們知道兩個(gè)具有相同hero.id的對(duì)象其實(shí)是同一個(gè)英雄。 下面就是這樣一個(gè)函數(shù):

    trackByHeroes(index: number, hero: Hero) { return hero.id; }

    現(xiàn)在,把NgForTrackBy指令設(shè)置為那個(gè)追蹤函數(shù)。

    <div *ngFor="let hero of heroes; trackBy:trackByHeroes">({{hero.id}}) {{hero.fullName}}</div>

    追蹤函數(shù)不會(huì)阻止所有 DOM 更改。 如果同一個(gè)英雄的屬性變化了,Angular 就可能不得不更新DOM元素。 但是如果這個(gè)屬性沒有變化 —— 而且大多數(shù)時(shí)候它們不會(huì)變化 —— Angular 就能留下這些 DOM 元素。列表界面就會(huì)更加平滑,提供更好的響應(yīng)。

    這里是關(guān)于NgForTrackBy效果的插圖。

    * 與 <template>

    當(dāng)審視NgFor、NgIf和NgSwitch這些內(nèi)置指令時(shí),我們使用了一種古怪的語法:出現(xiàn)在指令名稱前面的星號(hào) (*)。

    *是一種語法糖,它讓那些需要借助模板來修改 HTML 布局的指令更易于讀寫。?NgFor、NgIf和NgSwitch都會(huì)添加或移除元素子樹,這些元素子樹被包裹在<template>標(biāo)簽中。

    我們沒有看到<template>標(biāo)簽,那是因?yàn)檫@種*前綴語法讓我們忽略了這個(gè)標(biāo)簽, 而把注意力直接聚焦在所要包含、排除或重復(fù)的那些 HTML 元素上。

    這一節(jié),將深入研究一下,看看 Angular 是怎樣扒掉這個(gè)*,把這段 HTML 展開到<template>標(biāo)簽中的。

    展開*ngIf

    我們可以像 Angular 一樣,自己把*前綴語法展開成 template 語法,這里是*ngIf的一些代碼:

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

    currentHero被引用了兩次,第一次是作為NgIf的真 / 假條件,第二次把實(shí)際的 hero 值傳給了HeroDetailComponent。

    展開的第一步是把ngIf(沒有*前綴)和它的內(nèi)容傳給表達(dá)式,再賦值給template指令。

    <hero-detail template="ngIf:currentHero" [hero]="currentHero"></hero-detail>

    下一步,也是最后一步,是把 HTML 包裹進(jìn)<template>標(biāo)簽和[ngIf]屬性綁定中:

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

    注意,[hero]="currengHero"綁定留在了模板中的子元素<hero-detail>上。

    別忘了方括號(hào)!

    不要誤寫為ngIf="currentHero"! 這種語法會(huì)把一個(gè)字符串"currentHero"賦值給ngIf。 在 JavaScript 中,非空的字符串是真值,所以ngIf總會(huì)是true,而 Angular 將永遠(yuǎn)顯示hero-detail…… 即使根本沒有currentHero!

    展開*ngSwitch

    類似的轉(zhuǎn)換也適用于*ngSwitch。我們可以自己解開這個(gè)語法糖。 下例中,首先是*ngSwitchCase和*ngSwitchDefault,然后再解出<template>標(biāo)簽:

    <span [ngSwitch]="toeChoice"> <!-- with *NgSwitch --> <span *ngSwitchCase="'Eenie'">Eenie</span> <span *ngSwitchCase="'Meanie'">Meanie</span> <span *ngSwitchCase="'Miney'">Miney</span> <span *ngSwitchCase="'Moe'">Moe</span> <span *ngSwitchDefault>other</span> <!-- with <template> --> <template [ngSwitchCase]="'Eenie'"><span>Eenie</span></template> <template [ngSwitchCase]="'Meanie'"><span>Meanie</span></template> <template [ngSwitchCase]="'Miney'"><span>Miney</span></template> <template [ngSwitchCase]="'Moe'"><span>Moe</span></template> <template ngSwitchDefault><span>other</span></template> </span>

    *ngSwitchWhen和*ngSwitchDefault用和*ngIf完全相同的方式展開,把它們以前的元素包裹在<template>標(biāo)簽中。

    現(xiàn)在,應(yīng)該明白為什么ngSwitch本身不能用星號(hào) (*) 前綴了吧? 它沒有定義內(nèi)容,它的工作是控制一組模板。

    上面這種情況下,它管理兩組NgSwitchCase和NgSwitchDefault指令,一次是 (*) 前綴的版本,一次是展開模板后的版本。 我們也期待它顯示所選模板的值兩次。這正是在這個(gè)例子中看到的:

    展開*ngFor

    *ngFor也經(jīng)歷類似的轉(zhuǎn)換。從一個(gè)*ngFor的例子開始:

    <hero-detail *ngFor="let hero of heroes; trackBy:trackByHeroes" [hero]="hero"></hero-detail>

    這里是在把ngFor傳進(jìn)template指令后的同一個(gè)例子:

    <hero-detail template="ngFor let hero of heroes; trackBy:trackByHeroes" [hero]="hero"></hero-detail>

    下面,它被進(jìn)一步擴(kuò)展成了包裹著原始<hero-detail>元素的<template>標(biāo)簽:

    <template ngFor let-hero [ngForOf]="heroes" [ngForTrackBy]="trackByHeroes"> <hero-detail [hero]="hero"></hero-detail> </template>

    NgFor的代碼相對(duì)NgIf更復(fù)雜一點(diǎn),因?yàn)橹貜?fù)器有更多活動(dòng)部分需要配置。 這種情況下,我們就得記住添加NgForOf指令和NgForTrackBy指令,并對(duì)它們賦值。 使用*ngFor語法比直接寫這些展開后的 HTML 本身要簡單多了。

    模板引用變量

    模板引用變量是模板中對(duì) DOM 元素或指令的引用。

    它能在原生 DOM 元素中使用,也能用于 Angular 組件 —— 實(shí)際上,它可以和任何自定義 Web 組件協(xié)同工作。

    引用模板引用變量

    可以在同一元素、兄弟元素或任何子元素中引用模板引用變量。

    不要在同一個(gè)模版中多次定義相同變量名,否則運(yùn)行時(shí)的值將會(huì)不可預(yù)測(cè)。

    這里是關(guān)于創(chuàng)建和使用模板引用變量的另外兩個(gè)例子:

    <!-- phone refers to the input element; pass its `value` to an event handler --> <input #phone placeholder="phone number"> <button (click)="callPhone(phone.value)">Call</button> <!-- fax refers to the input element; pass its `value` to an event handler --> <input ref-fax placeholder="fax number"> <button (click)="callFax(fax.value)">Fax</button>

    "phone" 的井號(hào) (#) 前綴表示定義了一個(gè)phone變量。

    有些人不喜歡使用#字符,而是使用它的規(guī)范形式:ref-前綴。 例如,既能用#phone,也能用ref-phone來定義phone變量。

    如何獲取變量的值

    Angular 把這種變量的值設(shè)置為它所在的那個(gè)元素。 在這個(gè)input元素上定義了這些變量。 把那些input元素對(duì)象傳給 button 元素,在事件綁定中,它們作為參數(shù)傳給了call方法。

    NgForm 和模板引用變量

    讓我們看看最后一個(gè)例子:表單,使用模板引用變量的典范。

    正如在表單一章中所見過的,表單的 HTML 可以做得相當(dāng)復(fù)雜。 下面是簡化過的范例 —— 雖然仍算不上多簡單。

    <form (ngSubmit)="onSubmit(theForm)" #theForm="ngForm"> <div class="form-group"> <label for="name">Name</label> <input class="form-control" name="name" required [(ngModel)]="currentHero.firstName"> </div> <button type="submit" [disabled]="!theForm.form.valid">Submit</button> </form>

    模板引用變量theForm在這個(gè)例子中出現(xiàn)了三次,中間隔著一大段 HTML。

    <form (ngSubmit)="onSubmit(theForm)" #theForm="ngForm"> <button type="submit" [disabled]="!theForm.form.valid">Submit</button> </form>

    theForm變量的值是什么?

    如果 Angular 沒有接管它,那它可能是個(gè)HTMLFormElement。 實(shí)際上它是個(gè)ngForm,對(duì) Angular 內(nèi)置指令NgForm的引用。 它包裝了原生的HTMLFormElement并賦予它更多超能力,比如跟蹤用戶輸入的有效性。

    這解釋了該如何通過檢查theForm.form.valid來禁用提交按鈕,以及如何把一個(gè)信息量略大的對(duì)象傳給父組件的onSubmit方法。(譯注:onSubmit方法可能會(huì)出發(fā)事件,被父組件監(jiān)聽,參見下面的輸入和輸出屬性和父組件監(jiān)聽子組件的事件。)

    輸入與輸出屬性

    迄今為止,我們主要聚焦在綁定聲明的右側(cè),學(xué)習(xí)如何在模板表達(dá)式和模板語句中綁定到組件成員。 當(dāng)成員出現(xiàn)在這個(gè)位置上,則稱之為數(shù)據(jù)綁定的

    本節(jié)則專注于綁定到的目標(biāo),它位于綁定聲明中的左側(cè)。 這些指令的屬性必須被聲明成輸入輸出

    記住:所有組件皆為指令

    我們要重點(diǎn)突出下綁定目標(biāo)和綁定的區(qū)別。

    綁定的目標(biāo)是在=左側(cè)的部分,?源則是在=右側(cè)的部分。

    綁定的目標(biāo)是綁定符:[]、()或[()]中的屬性或事件名,?源則是引號(hào) (" ") 中的部分或插值符號(hào) ({{}}) 中的部分。

    指令中的每個(gè)成員都會(huì)自動(dòng)在綁定中可用。 不需要特別做什么,就能在模板表達(dá)式或語句中訪問指令的成員。

    訪問目標(biāo)指令中的成員則受到限制。 只能綁定到那些顯式標(biāo)記為輸入或輸出的屬性。

    在下面的例子中,iconUrl和onSave是組件的成員,它們?cè)?#61;右側(cè)引號(hào)語法中被引用了。

    <img [src]="iconUrl"/> <button (click)="onSave()">Save</button>

    它們既不是組件的輸入也不是輸出。它們是綁定的數(shù)據(jù)源。

    現(xiàn)在,看看HeroDetailComponent,它是綁定的目標(biāo)

    <hero-detail [hero]="currentHero" (deleteRequest)="deleteHero($event)"> </hero-detail>

    HeroDetailComponent.hero和HeroDetailComponent.deleteRequest都在綁定聲明的左側(cè)。?HeroDetailComponent.hero在方括號(hào)中,它是屬性綁定的目標(biāo)。?HeroDetailComponent.deleteRequest在圓括號(hào)中,它是事件綁定的目標(biāo)。

    聲明輸入和輸出屬性

    目標(biāo)屬性必須被顯式的標(biāo)記為輸入或輸出。

    當(dāng)我們深入HeroDetailComponent內(nèi)部時(shí),就會(huì)看到這些屬性被裝飾器標(biāo)記成了輸入和輸出屬性。

    @Input() hero: Hero; @Output() deleteRequest = new EventEmitter<Hero>();

    另外,還可以在指令元數(shù)據(jù)的inputs或outputs數(shù)組中標(biāo)記出這些成員。比如這個(gè)例子:

    @Component({inputs: ['hero'], outputs: ['deleteRequest'], })

    既可以通過裝飾器,也可以通過元數(shù)據(jù)數(shù)組來指定輸入/輸出屬性。但別同時(shí)用!

    輸入還是輸出?

    輸入屬性通常接收數(shù)據(jù)值。?輸出屬性暴露事件生產(chǎn)者,如EventEmitter對(duì)象。

    輸入和輸出這兩個(gè)詞是從目標(biāo)指令的角度來說的。

    從HeroDetailComponent角度來看,HeroDetailComponent.hero是個(gè)輸入屬性, 因?yàn)閿?shù)據(jù)流從模板綁定表達(dá)式流入那個(gè)屬性。

    從HeroDetailComponent角度來看,HeroDetailComponent.deleteRequest是個(gè)輸出屬性, 因?yàn)槭录哪莻€(gè)屬性流出,流向模板綁定語句中的處理器。

    給輸入/輸出屬性起別名

    有時(shí)需要讓輸入/輸出屬性的公開名字不同于內(nèi)部名字。

    這是使用?attribute 指令時(shí)的常見情況。 指令的使用者期望綁定到指令名。例如,在<div>上用myClick選擇器應(yīng)用指令時(shí), 希望綁定的事件屬性也叫myClick。

    <div (myClick)="clickMessage=$event">click with myClick</div>

    然而,在指令類中,直接用指令名作為自己的屬性名通常都不是好的選擇。 指令名很少能描述這個(gè)屬性是干嘛的。?myClick這個(gè)指令名對(duì)于用來發(fā)出 click 消息的屬性就算不上一個(gè)好名字。

    幸運(yùn)的是,可以使用約定俗成的公開名字,同時(shí)在內(nèi)部使用不同的名字。 在上面例子中,實(shí)際上是把myClick這個(gè)別名指向了指令自己的clicks屬性。

    把別名傳進(jìn)@Input/@Output裝飾器,就可以為屬性指定別名,就像這樣:

    @Output('myClick') clicks = new EventEmitter<string>(); // @Output(alias) propertyName = ...

    也可在inputs和outputs數(shù)組中為屬性指定別名。 可以寫一個(gè)冒號(hào) (:) 分隔的字符串,左側(cè)是指令中的屬性名,右側(cè)則是公開的別名。

    @Directive({outputs: ['clicks:myClick'] // propertyName:alias })

    模板表達(dá)式操作符

    模板表達(dá)式語言使用了 JavaScript 語法的子集,并補(bǔ)充了幾個(gè)用于特定場(chǎng)景的特殊操作符。 下面介紹其中的兩個(gè):管道和安全導(dǎo)航操作符。

    ?

    管道操作符 ( | )

    在綁定之前,表達(dá)式的結(jié)果可能需要一些轉(zhuǎn)換。例如,可能希望把數(shù)字顯示成金額、強(qiáng)制文本變成大寫,或者過濾列表以及進(jìn)行排序。

    Angular?管道對(duì)像這樣的小型轉(zhuǎn)換來說是個(gè)明智的選擇。 管道是一個(gè)簡單的函數(shù),它接受一個(gè)輸入值,并返回轉(zhuǎn)換結(jié)果。 它們很容易用于模板表達(dá)式中,只要使用管道操作符 (|)?就行了。

    <div>Title through uppercase pipe: {{title | uppercase}}</div>

    管道操作符會(huì)把它左側(cè)的表達(dá)式結(jié)果傳給它右側(cè)的管道函數(shù)。

    還可以通過多個(gè)管道串聯(lián)表達(dá)式:

    <!-- Pipe chaining: convert title to uppercase, then to lowercase --> <div> Title through a pipe chain: {{title | uppercase | lowercase}} </div>

    還能對(duì)它們使用參數(shù):

    <!-- pipe with configuration argument => "February 25, 1970" --> <div>Birthdate: {{currentHero?.birthdate | date:'longDate'}}</div>

    json管道對(duì)調(diào)試綁定特別有用:

    <div>{{currentHero | json}}</div>

    它生成的輸出是類似于這樣的:

    { "firstName": "Hercules", "lastName": "Son of Zeus", "birthdate": "1970-02-25T08:00:00.000Z", "url": "http://www.imdb.com/title/tt0065832/", "rate": 325, "id": 1 }

    ?

    安全導(dǎo)航操作符 ( ?. ) 和空屬性路徑

    Angular 的安全導(dǎo)航操作符 (?.)?是一種流暢而便利的方式,用來保護(hù)出現(xiàn)在屬性路徑中 null 和 undefined 值。 下例中,當(dāng)currentHero為空時(shí),保護(hù)視圖渲染器,讓它免于失敗。

    The current hero's name is {{currentHero?.firstName}}

    我們來詳細(xì)闡述一下這個(gè)問題和解決方案:

    如果下列數(shù)據(jù)綁定中title屬性為空,會(huì)發(fā)生什么?

    The title is {{title}}

    這個(gè)視圖仍然被渲染出來,但是顯示的值是空;只能看到 “The title is”,它后面卻沒有任何東西。 這是合理的行為。至少應(yīng)用沒有崩潰。

    假設(shè)模板表達(dá)式涉及屬性路徑,在下例中,顯示一個(gè)空 (null) 英雄的firstName。

    The null hero's name is {{nullHero.firstName}}

    JavaScript 拋出了空引用錯(cuò)誤,Angular 也是如此:

    TypeError: Cannot read property 'firstName' of null in [null].

    暈,整個(gè)視圖都不見了。

    如果確信hero屬性永遠(yuǎn)不可能為空,可以聲稱這是合理的行為。 如果它必須不能為空,但它仍然是空值,實(shí)際上是制造了一個(gè)編程錯(cuò)誤,它應(yīng)該被捕獲和修復(fù)。 這種情況應(yīng)該拋出異常。

    另一方面,屬性路徑中的空值可能會(huì)時(shí)常發(fā)生,特別是當(dāng)我們知道數(shù)據(jù)最終會(huì)出現(xiàn)。

    當(dāng)?shù)却龜?shù)據(jù)的時(shí)候,視圖渲染器不應(yīng)該抱怨,而應(yīng)該把這個(gè)空屬性路徑顯示為空白,就像上面title屬性那樣。

    不幸的是,當(dāng)currentHero為空的時(shí)候,應(yīng)用崩潰了。

    可以通過寫NgIf代碼來解決這個(gè)問題。

    <!--No hero, div not displayed, no error --> <div *ngIf="nullHero">The null hero's name is {{nullHero.firstName}}</div>

    或者可以嘗試通過&&來把屬性路徑的各部分串起來,讓它在遇到第一個(gè)空值的時(shí)候,就返回空。

    The null hero's name is {{nullHero && nullHero.firstName}}

    這些方法都有價(jià)值,但是會(huì)顯得笨重,特別是當(dāng)這個(gè)屬性路徑非常長的時(shí)候。 想象一下在一個(gè)很長的屬性路徑(如a.b.c.d)中對(duì)空值提供保護(hù)。

    Angular 安全導(dǎo)航操作符 (?.) 是在屬性路徑中保護(hù)空值的更加流暢、便利的方式。 表達(dá)式會(huì)在它遇到第一個(gè)空值的時(shí)候跳出。 顯示是空的,但應(yīng)用正常工作,而沒有發(fā)生錯(cuò)誤。

    <!-- No hero, no problem! --> The null hero's name is {{nullHero?.firstName}}

    在像a?.b?.c?.d這樣的長屬性路徑中,它工作得很完美。

    轉(zhuǎn)載于:https://www.cnblogs.com/shitoupi/p/6622878.html

    總結(jié)

    以上是生活随笔為你收集整理的angular2的模板语法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

    欧美日韩中文在线 | 黄色日视频 | 亚洲一片黄 | 91免费高清视频 | 欧美在线1 | 夜夜视频 | aav在线| 亚州精品一二三区 | 99精品一区二区三区 | 久久精品国产精品亚洲 | 久99久精品视频免费观看 | 精品国产亚洲在线 | 久久成人午夜视频 | 麻豆视频网址 | 国产精选在线观看 | 狠狠狠色丁香婷婷综合久久88 | 中文字幕在线播放日韩 | 免费看的国产视频网站 | 色综合咪咪久久网 | 国产在线观看黄 | 免费在线观看av不卡 | 久久精品精品 | 午夜三级影院 | 精品久久久久久亚洲综合网站 | 国产精品国产三级国产aⅴ9色 | 国产视频二 | 黄免费网站 | 日日爱网站 | 中文字幕久久精品 | 久久久久成人精品 | 国产日本三级 | 国产亚洲精品久久久久久久久久 | 中文视频在线看 | 黄色软件视频大全免费下载 | 成人在线观看你懂的 | 日日操网| 国产在线综合视频 | 国内精品亚洲 | 欧美一级黄色视屏 | 日韩免费视频在线观看 | 精品视频www | 国产精品videossex国产高清 | 日韩成人欧美 | 91精品一区国产高清在线gif | 日韩欧美国产免费播放 | 黄色一级免费电影 | 免费看三级 | 五月天亚洲精品 | 综合久久精品 | 麻豆观看| 在线国产福利 | 香蕉网站在线观看 | 99视频在线精品国自产拍免费观看 | 日日夜夜天天综合 | 五月天九九 | 国产 日韩 在线 亚洲 字幕 中文 | 日韩成人av在线 | 久久久久国产一区二区三区 | 欧美精品一区二区性色 | 一区二区不卡在线观看 | 中文字幕在线看片 | 久久久久免费精品国产小说色大师 | 日韩av在线影视 | 国产一区二区在线免费视频 | 人人看人人艹 | 91麻豆精品国产91久久久久久 | 99视频国产精品 | 91精品国产福利在线观看 | 国产精品自产拍在线观看 | 精品国产一二区 | 奇米7777狠狠狠琪琪视频 | 国产黄色精品 | 亚洲一二区视频 | 欧美了一区在线观看 | 综合色站导航 | 99久久精品费精品 | 成人国产在线 | av大全在线| 国产 视频 久久 | 91精品视频免费看 | 五月开心综合 | 日韩在线观看三区 | 在线小视频 | 成人国产精品电影 | 免费日韩电影 | 日韩欧美综合在线视频 | 久久久久久久影院 | 手机在线看a | 中文字幕视频免费观看 | 狠狠婷婷 | 久久久久久久99精品免费观看 | av免费看网站 | 久久久久国产一区二区三区 | 91桃色国产在线播放 | 日韩精选在线 | 91av在线免费播放 | 一区二区三区在线视频观看58 | 九九九九九九精品 | 欧美黄色高清 | 成人黄色在线观看视频 | 久久久久久久久久电影 | 久久综合影院 | 欧美动漫一区二区三区 | av播放在线 | 国产成人精品一区二区 | 日韩高清二区 | 亚洲国产精品日韩 | 成人资源在线播放 | 欧美美女视频在线观看 | 91在线看视频免费 | 成人av动漫在线 | 国产成人久久精品77777综合 | 久久免费视频播放 | 欧美日韩精品在线观看 | 狠狠躁夜夜躁人人爽超碰97香蕉 | 国产不卡av在线 | 99久久精品国产一区二区成人 | 九九视频免费在线观看 | 国产精品久免费的黄网站 | 亚洲人天堂 | 精品在线一区二区 | 91.精品高清在线观看 | 综合色在线 | 激情五月网站 | 久久美女视频 | 99精品在线视频观看 | 2024国产精品视频 | 国内精品久久天天躁人人爽 | 亚洲成人av免费 | 中文字幕电影高清在线观看 | 久久免费资源 | 日韩久久影院 | 国产一区二区手机在线观看 | 五月婷婷亚洲 | 天堂av免费在线 | 色婷婷激情五月 | 免费视频久久久 | 欧美精品久久久久久久久久白贞 | 亚洲精品中文字幕在线观看 | 久久国产精品免费一区二区三区 | 亚洲一区日韩精品 | 国产午夜精品av一区二区 | 黄网站a| 美女久久久久久 | 国产精品久久久久久久久软件 | 色婷婷综合视频在线观看 | 国产精品av电影 | 99久久日韩精品免费热麻豆美女 | 91在线小视频 | 麻豆成人小视频 | 一 级 黄 色 片免费看的 | 久久伦理 | 99热.com| 国产精品情侣视频 | 国产免费xvideos视频入口 | 男女日麻批 | 亚洲九九九在线观看 | 免费观看一区二区 | 97在线精品国自产拍中文 | 欧美日韩国产综合一区二区 | 亚洲精品在线播放视频 | 国外调教视频网站 | 国产对白av | 国产二区精品 | 中文字幕av在线电影 | 成人午夜精品福利免费 | 97电影手机 | 天天躁日日躁狠狠躁av中文 | 日本久久久久久 | 国产资源在线免费观看 | 国产精品久久久久免费观看 | 欧美一区免费观看 | 亚洲成熟女人毛片在线 | 国产乱码精品一区二区蜜臀 | 国内精品亚洲 | 成在人线av | www.亚洲黄| 国产玖玖在线 | 在线观看黄 | 久久狠狠亚洲综合 | 最新国产精品久久精品 | 看毛片网站 | 亚洲精品乱码 | 亚洲黄色a| 夜夜操天天干 | www.com.日本一级| 免费在线观看午夜视频 | 亚洲精品小视频 | 国内外成人在线视频 | 久久久久激情电影 | 日韩成人免费电影 | 91精品国自产拍天天拍 | av韩国在线 | 99热日本 | 欧美另类xxx | 国产小视频你懂的在线 | 久久久污 | 97色婷婷成人综合在线观看 | 在线一区av| 粉嫩一二三区 | 亚洲九九影院 | 最近2019年日本中文免费字幕 | av在线播放网址 | 九九精品视频在线观看 | 午夜aaaa | 黄网站免费久久 | 99久久精品久久久久久动态片 | 亚洲免费视频在线观看 | 色狠狠久久av五月综合 | 美女国产网站 | 97国产小视频 | 久久国产亚洲视频 | 狠狠色丁香婷婷综合久小说久 | 丁香激情综合久久伊人久久 | 亚洲.www| 99在线观看视频网站 | 顶级bbw搡bbbb搡bbbb | 精品自拍av | 97视频在线播放 | 日日干夜夜草 | 亚洲第一成网站 | 国产在线国偷精品产拍 | 免费在线一区二区 | 日韩国产精品久久久久久亚洲 | 日韩精品中文字幕av | 日韩在线观看视频一区二区三区 | 亚洲综合情 | 日韩r级在线 | 在线中文视频 | 国产精品一区二区久久久久 | 国产麻豆精品一区 | 日韩a在线播放 | 国产精品久久久久久电影 | 五月天婷亚洲天综合网鲁鲁鲁 | 国产一区二区免费在线观看 | 在线观看国产一区二区 | 国产a级片免费观看 | 国产丝袜网站 | 麻豆果冻剧传媒在线播放 | 不卡中文字幕在线 | 亚洲欧美国产精品18p | 四虎永久免费网站 | 亚洲精品网址在线观看 | 在线国产视频一区 | 六月激情久久 | 91成人精品一区在线播放69 | 久久福利| 精品久久久久久一区二区里番 | 婷婷亚洲五月色综合 | 深爱激情久久 | 五月婷婷另类国产 | 精品中文字幕视频 | 99久久精品免费看国产一区二区三区 | av电影在线免费 | 亚洲va天堂va欧美ⅴa在线 | 欧美日韩久久 | 亚洲国产欧洲综合997久久, | 久久天天拍 | 欧美射射射| 色搞搞| 国产视频首页 | www.狠狠操 | 欧美精品免费在线观看 | 人人玩人人添人人澡超碰 | 毛片永久新网址首页 | 特黄特色特刺激视频免费播放 | 9999亚洲 | 久精品视频免费观看2 | 99亚洲精品视频 | 一区二区三区中文字幕在线 | 国产精品成人一区二区三区 | 免费色网| 人人澡人人草 | 国产一区在线视频 | a色视频 | 欧美精品在线观看免费 | 亚洲九九九在线观看 | 五月激情丁香图片 | 97在线观看免费观看 | 精品久久久一区二区 | 色噜噜狠狠色综合中国 | 波多野结衣视频一区二区三区 | 欧美国产大片 | 亚洲精品在线观看免费 | 久久人人爽人人爽人人片 | 91香蕉视频黄色 | 中文字幕在线视频一区 | 一区二区精品在线 | 色视频在线观看免费 | 欧美精品免费一区二区 | 欧美日韩伦理一区 | 手机版av在线| 高清av不卡| 在线免费国产视频 | 91看片看淫黄大片 | 中文字幕在线视频免费播放 | 久久久免费精品国产一区二区 | 国产精品毛片一区视频播不卡 | 中文字幕在线国产 | 在线观看av不卡 | 一区二区中文字幕在线观看 | aaa毛片视频 | 国产精品一区二区av麻豆 | 精品国内自产拍在线观看视频 | 亚洲另类视频在线观看 | 久久av免费观看 | 国产福利小视频在线 | 天天操狠狠操网站 | 亚洲精品一区二区精华 | 天天搞夜夜骑 | 精品国产美女 | 国产精品专区在线观看 | 丁香久久综合 | 婷婷丁香激情五月 | 久久永久免费视频 | 日韩在线播放av | 91高清不卡| aaaaaa毛片| 一区二区视频网站 | 亚洲开心激情 | 婷婷看片| 成人精品国产免费网站 | 黄影院| 五月天网站在线 | av黄免费看 | 亚洲 欧美变态 另类 综合 | 日韩成人免费电影 | 91系列在线观看 | 国产午夜精品av一区二区 | 丁五月婷婷 | 99久久精品费精品 | 91天堂在线观看 | 欧美日韩不卡一区二区三区 | 欧洲精品码一区二区三区免费看 | 中文字幕免费高 | 色视频在线免费 | 成人永久视频 | 亚色视频在线观看 | 免费视频99| 国产美女被啪进深处喷白浆视频 | 99久久久久久久久久 | 亚洲在线成人精品 | 午夜视频在线观看网站 | 欧美日韩精品二区第二页 | 亚洲一区二区三区四区在线视频 | 在线看片一区 | 国产精品久久久久国产精品日日 | 日本99热| 日韩av免费一区 | 99热高清 | 日韩综合精品 | 国产高清视频免费在线观看 | 又爽又黄又刺激的视频 | 日韩中文字幕免费在线播放 | 在线看国产| 66av99精品福利视频在线 | 成人av一区二区在线观看 | 亚洲精品88欧美一区二区 | 精品久久久免费视频 | 久久99精品国产一区二区三区 | 国产亚洲资源 | 蜜臀久久99精品久久久久久网站 | 在线观看一区二区精品 | 日韩精品三区四区 | 精品国产_亚洲人成在线 | 国产精品一区二区久久精品 | 亚洲国产精品va在线看黑人动漫 | av中文字幕在线看 | 青青河边草免费 | 国产精品一区二区三区久久 | 麻豆视频免费播放 | 99热99热| www.xxx.性狂虐| 九九久久免费视频 | 黄污污网站 | 中文字幕国产一区 | 欧美日韩91 | 四虎影视精品永久在线观看 | 91网站在线视频 | 精品久久久久久亚洲综合网站 | 亚洲1级片 | 国产成人精品一区二区三区福利 | 亚洲在线网址 | 久久久av电影 | 天天干天天操天天爱 | 日韩精品 在线视频 | 精品国产亚洲一区二区麻豆 | 国产打女人屁股调教97 | 91字幕 | 国产自产在线视频 | 日韩欧美国产成人 | 久久9999久久免费精品国产 | 日韩成片 | 美女久久网站 | 国产精成人品免费观看 | 特黄特色特刺激视频免费播放 | 96精品视频 | 亚洲国产视频直播 | 免费黄色在线网站 | 国产一级a毛片视频爆浆 | 91av视频在线观看 | 日韩高清av在线 | 欧美激情va永久在线播放 | 国产精品大全 | 久久免费视频8 | 婷婷丁香九月 | 色综合久久88色综合天天 | 国产91成人| 国产手机在线观看 | 96av麻豆蜜桃一区二区 | 久久婷婷一区二区三区 | 日本一区二区三区免费观看 | 天天操天天射天天 | 久久精品国产99 | 婷婷精品国产欧美精品亚洲人人爽 | 国产999精品久久久久久 | 成人久久久久久久久 | 欧美韩国在线 | 激情五月婷婷 | 在线天堂v| 日本爱爱免费 | 欧美专区国产专区 | 日韩精品一区二区三区视频播放 | 国产免费叼嘿网站免费 | 亚洲精品自拍 | 五月天伊人网 | 天天操天天干天天 | 亚洲国产精品女人久久久 | 五月天久久婷 | 免费看一级特黄a大片 | 免费欧美高清视频 | 日韩免费大片 | 中文字幕在线观看你懂的 | 亚洲精品色婷婷 | 91日韩免费| 成人91免费视频 | 久久久久高清毛片一级 | 免费一级片视频 | 国产精品一区在线观看 | 久久66热这里只有精品 | 免费亚洲精品 | 国产色啪 | 国产精选在线 | 久久综合久久88 | 在线观看黄色 | 国产高清精品在线观看 | 国产美女无遮挡永久免费 | 国产美女视频一区 | 亚洲第一中文网 | 日韩美在线 | 亚洲电影免费 | 国产成人在线免费观看 | 色午夜 | 免费看污在线观看 | 亚洲精品h | 久久午夜精品视频 | 日韩成片| 亚洲成人一区 | 91理论电影| 园产精品久久久久久久7电影 | 日本一区二区三区视频在线播放 | 久久久色 | 干干夜夜| 久久久麻豆视频 | 超碰在线人人爱 | 四月婷婷在线观看 | 五月婷婷综合在线 | 在线观看日韩国产 | 国产一级淫片在线观看 | 久久精品爱爱视频 | 久免费视频 | 24小时日本在线www免费的 | 国产一区免费在线观看 | 狠狠狠狠狠狠狠狠 | 亚洲三级在线免费观看 | 欧美日韩中字 | 欧美三级在线播放 | 国产精品国产三级在线专区 | 嫩模bbw搡bbbb搡bbbb | 你操综合 | 天天插天天干天天操 | 午夜精品久久久久久久99 | 永久中文字幕 | 六月色婷婷| 青青射 | 国产免费一区二区三区最新6 | 日韩免费视频线观看 | 中文字幕 第二区 | 日韩二区在线观看 | 国产亚洲综合在线 | 婷婷天天色| 国产精品18久久久久久首页狼 | 亚洲涩综合 | 在线中文字幕观看 | 日韩精品高清不卡 | 国产高清视频免费最新在线 | 国产一区二区高清 | 国产精品综合av一区二区国产馆 | 开心色婷婷 | 99国产成+人+综合+亚洲 欧美 | 久久精品中文字幕一区二区三区 | 亚洲午夜久久久久久久久 | 91精品国产网站 | 久草在线视频资源 | 99精品视频精品精品视频 | 999抗病毒口服液 | 日韩爱爱网站 | 美女免费黄视频网站 | 天天操天天怕 | 激情图片区 | 国产在线观看你懂得 | 97视频在线播放 | 亚洲日日日 | 97超视频免费观看 | 天天在线免费视频 | 国产午夜视频在线观看 | 国产精品毛片一区二区在线 | 欧美a视频在线观看 | 日本久久久精品视频 | 91精品视频免费看 | 亚洲h视频在线 | 日日爱视频 | 91福利免费 | 欧美va天堂在线电影 | 久青草视频在线观看 | 亚洲综合视频在线 | 免费网站黄 | 国产在线日本 | 久久久久综合网 | 免费观看xxxx9999片 | 亚洲特级片 | 国产原创中文在线 | av在线影视 | 日韩免费小视频 | 91精品欧美 | 亚洲资源在线观看 | 制服丝袜一区二区 | 日韩一区二区三区高清免费看看 | 99色在线观看视频 | 亚洲国产中文字幕 | 超级碰99| www.午夜色.com | 国产精品久久久久久久久久久杏吧 | 久久国产亚洲 | 亚洲一级黄色片 | 三级av在线免费观看 | 久久久久久久久久久黄色 | 久久超碰97| 99九九热只有国产精品 | 日韩一级电影网站 | 97国产视频 | 国产日韩欧美在线影视 | 亚洲综合五月天 | 波多野结衣理论片 | 国产97视频在线 | 四虎成人免费影院 | 免费毛片一区二区三区久久久 | 人人玩人人添人人澡超碰 | 国产精品久久久久影院 | 97在线视频免费观看 | 97在线资源 | 一区二区三区免费网站 | 婷婷久月 | 久在线观看视频 | 久草精品网 | 国产精品av一区二区 | 亚洲欧洲精品一区 | 久草视频在线免费播放 | 91麻豆精品国产91久久久久 | 最近更新好看的中文字幕 | 中文字幕乱视频 | 国产精品女同一区二区三区久久夜 | 国产精品99久久久久久有的能看 | 在线色资源 | 97精品欧美91久久久久久 | 婷婷色网视频在线播放 | 伊人亚洲综合 | 91网在线观看 | 亚洲精品天天 | 97久久精品午夜一区二区 | av千婊在线免费观看 | 青春草视频在线播放 | 国产免费看| 精品福利视频在线 | 亚洲精品啊啊啊 | 欧美日韩在线视频一区 | 欧美日韩免费一区 | 精品国产精品久久 | 免费a级观看 | 久久国产精品色av免费看 | 久久婷婷精品 | av在线网站免费观看 | 夜夜骑天天操 | 黄色小说免费观看 | 久久久久免费精品国产 | 久久久久中文字幕 | 综合国产视频 | av九九| 国产成人久久精品77777综合 | 麻豆av电影 | 成人黄色电影在线 | 91一区啪爱嗯打偷拍欧美 | 视频三区 | 天天爽天天爽夜夜爽 | 91精品在线播放 | 91亚洲国产成人久久精品网站 | 97超碰人人模人人人爽人人爱 | 日日爽 | 欧美日韩在线观看一区二区 | 美女网站在线看 | 人人澡人人添人人爽一区二区 | 97视频免费看 | 国产亚洲精品久久 | 97精品国产97久久久久久免费 | 97超碰精品 | 亚洲最新视频在线播放 | 天天性天天草 | 特级片免费看 | 99 视频 高清| www.超碰 | 国产中文字幕一区 | 天天爽人人爽 | 黄污视频网站大全 | 亚洲极色 | 在线亚洲免费视频 | 国产片免费在线观看视频 | 欧美精品久久久久a | 国产美女久久久 | 亚洲闷骚少妇在线观看网站 | 欧美亚洲国产一卡 | 中文字幕av免费在线观看 | 亚洲成人软件 | 国产精品免费视频一区二区 | 国产九九在线 | 日韩视频免费观看高清 | 三级黄色网址 | 五月婷在线观看 | 国产视频欧美视频 | 精品国产免费av | 天天噜天天色 | 欧美色婷婷 | 狂野欧美激情性xxxx | 波多野结衣久久精品 | 91福利影院在线观看 | 午夜久久影视 | 中文成人字幕 | 天天干干 | 色天天久久 | 99久久精品国产毛片 | 成人免费在线网 | 日韩精品一区二区三区在线播放 | 视频精品一区二区三区 | 最近免费中文字幕mv在线视频3 | 一本一道久久a久久精品 | 九九精品无码 | 亚洲欧美日韩一级 | 国产在线v | 欧美久久久久 | 天天鲁天天干天天射 | 中文字幕免费国产精品 | 六月天色婷婷 | www天天干com | 免费福利片2019潦草影视午夜 | 天天操天天添 | 亚洲专区欧美 | 亚洲精品无 | 在线日韩中文字幕 | 免费av在线网站 | 五月婷丁香网 | 激情综合色图 | 日韩欧美xxxx| 91丨九色丨蝌蚪丰满 | 超碰人人草 | 在线观看亚洲电影 | 天天天天射 | 黄色在线网站噜噜噜 | 天天看天天干天天操 | 在线成人国产 | 99999精品| 国产一区二区网址 | 成人理论电影 | 久久综合五月婷婷 | 色多多在线观看 | 久热免费在线 | 91成人看片 | 日韩精品久久久久 | 精品一区二区视频 | 日韩国产精品一区 | 日色在线视频 | 色香蕉网 | 99久久久| 国产又粗又硬又爽视频 | 九九久久影院 | 天天操天天爽天天干 | 一区二区三区 亚洲 | av观看免费在线 | 欧美日本不卡视频 | 天天插天天爽 | 欧美激情精品久久久久久免费印度 | 九九综合在线 | 久久一久久 | 嫩草伊人久久精品少妇av | 在线一二三四区 | 综合网成人 | 久99热| 国产成人精品网站 | 国产精品久久久久av福利动漫 | 五月天婷婷在线观看视频 | 天天爽天天爽夜夜爽 | 黄av在线| 小草av在线播放 | 中国美女一级看片 | 天天干天天天 | 欧美污网站 | 久久国产精品免费 | 天天爽人人爽夜夜爽 | 国产v在线播放 | 免费大片av | 亚洲好视频 | 九色视频自拍 | 在线亚洲观看 | 999在线精品| 精品亚洲成人 | 午夜久久久久久久久久久 | 五月婷婷久| 久久久久国产成人免费精品免费 | 日韩高清国产精品 | 日韩字幕 | 久久久久女人精品毛片 | 久久久91精品国产 | 成人h电影在线观看 | 成人福利在线观看 | 亚洲成av| 免费一级特黄录像 | 人人盈棋牌 | 五月婷婷色综合 | 国产精品毛片久久久久久 | 欧美午夜寂寞影院 | 手机成人在线 | 国产精品欧美在线 | 国产成人三级三级三级97 | 久久久免费看 | 婷婷中文字幕综合 | 午夜色婷婷 | 久久精品一二区 | 黄色大片入口 | 国产一卡二卡在线 | 国内偷拍精品视频 | 日本精品午夜 | 91香蕉视频在线下载 | 久久国产香蕉视频 | 久久综合久久综合久久 | 久久国产亚洲视频 | 国产麻豆精品久久 | 欧美福利视频一区 | 午夜视频在线观看一区二区三区 | 日本中文字幕在线免费观看 | 久久婷婷国产 | 欧美成人一区二区 | 久久这里有精品 | 国产无吗一区二区三区在线欢 | 日韩欧美国产免费播放 | av先锋中文字幕 | 午夜a区 | 色天天综合网 | 欧美精品亚州精品 | 在线黄色毛片 | 天天色棕合合合合合合 | 日韩一区二区在线免费观看 | 五月的婷婷| 黄色一级动作片 | 欧美黑人性爽 | 黄色一级免费网站 | 四虎成人精品 | 欧美91精品国产自产 | 9在线观看免费高清完整版在线观看明 | 久久国产精品免费看 | 国产精品九九久久99视频 | 国产亚洲免费的视频看 | 久久国产精品一国产精品 | 国产99免费视频 | 黄色成人av网址 | av网站在线免费观看 | 叶爱av在线| 国产在线污 | 国产精品精品久久久久久 | 欧洲视频一区 | 9i看片成人免费看片 | 美女福利视频一区二区 | 蜜臀av一区二区 | 精品在线视频一区二区三区 | av经典在线 | 亚洲精品国产精品国自 | 黄色毛片网站在线观看 | www.天堂av| 国产一区二区久久精品 | 久久av高清 | 国产午夜在线观看视频 | 国产91精品一区二区 | 天天操天天弄 | 日韩视频在线观看免费 | 韩国中文三级 | 人人澡超碰碰 | 最新免费中文字幕 | 天天看天天干天天操 | 在线观看视频精品 | 亚洲精品国产精品久久99热 | 精品一区中文字幕 | 国产免费又粗又猛又爽 | 久久中文字幕在线视频 | 天天操狠狠干 | www视频在线免费观看 | 中文字幕在线观看1 | 天天干人人插 | 成人黄色免费观看 | 91在线日韩| 日韩精品一区二区三区中文字幕 | 日本不卡123 | 日本午夜免费福利视频 | 久久久影院官网 | 久久久精品在线观看 | 日本久久片 | 天天超碰 | 欧美美女视频在线观看 | 中文在线免费视频 | 久久久资源网 | 久久国产露脸精品国产 | 91精品国产99久久久久久红楼 | 国产精品专区一 | 五月婷婷激情网 | 午夜视频在线观看一区二区三区 | 国产成人av电影 | 在线亚洲午夜片av大片 | 国产黄色免费观看 | 奇米先锋| 欧美日韩在线第一页 | 国产又粗又硬又爽视频 | 一级黄色网址 | 婷婷国产视频 | 国产精品丝袜久久久久久久不卡 | 久久久久久久久久久网 | 久久www免费人成看片高清 | 国产精品一区电影 | 欧美最猛性xxxx | 手机成人av| 亚洲四虎影院 | 亚洲专区在线播放 | 久久精品高清视频 | 久久久久久看片 | 国产性天天综合网 | 久久不射网站 | 中文字幕文字幕一区二区 | 国产精品欧美久久久久三级 | 久草在线 | 久久久国产精品网站 | 免费色黄 | 国产在线日本 | 热久久国产精品 | 亚洲无吗视频在线 | 最新日韩电影 | 久久av免费观看 | 中文字幕91在线 | 免费人成在线观看网站 | 中文av在线播放 | 国产在线看一区 | 深夜成人av | 国产精品久久嫩一区二区免费 | 日韩视频在线播放 | 国产成人99久久亚洲综合精品 | 国内视频1区 | 大荫蒂欧美视频另类xxxx | 久久国产精品久久久 | 国产成人无码AⅤ片在线观 日韩av不卡在线 | 免费观看成人av | 99在线热播精品免费 | 日韩精品在线播放 | 日韩电影中文,亚洲精品乱码 | 亚洲精品美女在线观看播放 | 欧美日韩精品区 | 在线观看日韩专区 | 免费看黄在线观看 | 最新中文字幕在线观看视频 | 亚洲精品美女在线观看播放 | 久久久久久国产一区二区三区 | 国产中文字幕在线播放 | 一区三区视频在线观看 | 国产在线va | 精品久久久成人 | 最近中文字幕mv | 亚洲精品视频一 | 91精品啪在线观看国产线免费 | 精品国产1区二区 | 免费福利片2019潦草影视午夜 | 国产精华国产精品 | 四虎成人免费观看 | 国产在线欧美在线 | 国产成人久久av977小说 | 免费亚洲视频 | 中文字幕在线观看网址 | 婷婷激情影院 | 国产小视频在线播放 | 亚洲精品国产第一综合99久久 | 五月婷综合网 | 麻豆精品视频在线观看免费 | 96亚洲精品久久久蜜桃 | 丁香婷婷激情网 | 中文资源在线播放 | 欧美精品中文在线免费观看 | 91视频 - v11av | 日韩成人精品在线观看 | 色在线视频网 | 黄色一区三区 | 亚洲国产精品va在线看 | 欧美激情xxxx性bbbb | 欧美日韩在线播放一区 | 国产区高清在线 | 97精品国产97久久久久久免费 | 天天操伊人| 久爱精品在线 | 亚洲欧美乱综合图片区小说区 | 五月婷婷一级片 | av中文字幕网站 | 色av色av色av | 亚洲在线 | 夜夜操天天干, | 97高清免费视频 | 欧美精品资源 | 伊人亚洲综合网 | 免费视频一二三 | 日本精品视频一区 | 欧美日韩午夜爽爽 | 国产高清在线观看av | 久久无码av一区二区三区电影网 | 美女视频久久黄 | 波多野结衣在线视频免费观看 | 美女视频黄免费网站 | 久艹在线观看视频 | 天堂网av 在线| 天天摸天天舔天天操 | 午夜天使 | 亚洲国产成人高清精品 | 国产精品k频道 | 97色在线观看免费视频 | 丁香激情婷婷 | 免费网址你懂的 | 欧美日韩中文视频 | 91在线资源| av久久久久久 | 在线播放91 | 97人人模人人爽人人喊中文字 | 国产小视频你懂的在线 | 久久的色| 中文字幕乱码亚洲精品一区 | 久久永久免费视频 | 国产亚洲精品v | 日韩一片| 超碰97人人在线 | 欧美日韩视频精品 | 久久国产精品小视频 | 91插插视频 | 四虎永久免费 | 国产精品高 | 日日日爽爽爽 | 国产精品久久久久久久久久不蜜月 | 中文十次啦| av手机在线播放 | 国产成人精品在线播放 | .国产精品成人自产拍在线观看6 | 操操操com | 国产精品原创av片国产免费 | 亚洲乱码中文字幕综合 | 亚洲h在线播放在线观看h | 奇米影视777影音先锋 | 日韩有码第一页 | 国产 日韩 在线 亚洲 字幕 中文 | 天天操天天干天天爽 | 黄污视频大全 | 天天操天天爱天天爽 | 国产欧美精品一区aⅴ影院 99视频国产精品免费观看 | 久久久久女人精品毛片九一 | 五月天婷亚洲天综合网精品偷 | 91看片淫黄大片一级在线观看 | av观看网站 | 国产福利小视频在线 | 欧美成人精品在线 | www.91国产| 在线观av| 日韩高清不卡在线 | 97麻豆视频| 99精品视频一区 | 在线观看视频在线观看 | 国产精品成久久久久 | 日本爱爱片 | 91精品专区 | 精品国产一区二 | 国产精品第二十页 | 最新亚洲视频 | 91人人爽人人爽人人精88v |