Angular4 - 模板文法

來源:互聯網
上載者:User

Angular4 - 模板文法 1. 模板文法的介紹 HTML 是 Angular 模板的語言。幾乎所有的HTML文法都是有效模板文法。 但值得注意的例外是<script>元素,它被禁用了,以阻止指令碼插入式攻擊的風險。(實際上,<script>只是被忽略了。)
有些合法的 HTML 被用在模板中是沒有意義的。<html>、<body>和<base>元素這個舞台上中並沒有扮演有用的角色。剩下的所有元素基本上就都一樣用了。這些元素存在於index.html中。
可以通過組件和指令來擴充模板中的 HTML 詞彙。它們看上去就是新元素和屬性。

那麼模板文法是什麼呢。
對於一個簡單的html代碼,我們可以在頁面內配置css屬性,綁定事件,設計element元素的位置達到我們想要的結果。以此類推到Angular模板中來說。模板文法規定了以下內容(自我總結):
*規定了html詞彙(script被忽略,html,body,base沒有意義,擴充指令和組件)
*擴充插值運算式和擴充模板運算式
*擴充了綁定文法(規定了屬性綁定,事件綁定的文法以及雙向繫結內容)
*模板引用變數 (請查看組件章節)
*Angular內建指令 (本章不會講解,後續指令文章會有說明)
*Angular自訂指令 (本章不會講解,後續指令文章會有說明)


總而言之,模板文法是規定了我們操作template內容以達到我們想要的結果
2. 插值運算式和模板運算式 (1) 插值運算式 {{}}稱為插值運算式,可以將當前組件控制器中的公有變數直接取值然後顯示其值。

I am {{employee.name}}
//angular.component.tsexport class AngularComponent implements OnInit {  public employee: Employee = {    name: 'rodchen',    company: 'aug'  }  constructor() {  }  ngOnInit(): void {  }}
插值運算式還可以將計算過的字串插入到HTML元素標籤內或對標籤的屬性進行賦值
<h3>  {{title}}  <img src="{{heroImageUrl}}" style="height:30px"></h3>
(2) 模板運算式 模板運算式產生一個值。 Angular執行這個運算式,並把它賦值給繫結目標的屬性,這個繫結目標可能是 HTML 元素、組件或指令
。插值運算式其實就是模板運算式,只是上面我們只是將控制器中的變數值直接賦給元素。如果{{}}中發生了計算,那麼我們可以稱作模板運算式。模板運算式可以是數字計算
<p>The sum of 1 + 1 is {{1 + 1}}</p>
也可以是調用宿主組件的方法
<p>The sum of 1 + 1 is not {{1 + 1 + getVal()}}</p>
模板運算式看起來javascript運算式,但是是有一些規定:

JavaScript中那些具有或可能引發副作用的運算式是被禁止的,包括:
賦值 (=, +=, -=, ...)
new運算子
使用;或,的鏈式運算式
自增或自減操作符 (++和--)


和 JavaScript文法的其它顯著不同包括:
不支援位元運算|和&
具有新的模板運算式運算子,比如|、?.和!。


(3) 模板運算式操作符 a) 管道操作符 ( | ) 在綁定之前,運算式的結果可能需要一些轉換。例如,可能希望把數字顯示成金額、強制文本變成大寫,或者過濾列表以及進行排序。
I am {{employee.name | uppercase}} //I am RODCHEN
具體用法可以參照 pipe,後面也會有專門的文章去學習。
b) 安全導航操作符 ( ?. ) 和空屬性路徑 Angular 的安全導航操作符 (?.) 是一種流暢而便利的方式,用來保護出現在屬性路徑中 null 和 undefined 值。例如a)中的例子,如果employee是null,頁面會發生是什麼呢。
"I am"依然會渲染,但是會報錯。
TypeError: Cannot read property 'name' of null in [null]. 
這時我們就可以使用安全導航操作符來規避這個錯誤。
I am {{employee?.name | uppercase}}
c) 非空斷言操作符(!) 如果類型檢查器在運行期間無法確定一個變數是null或undefined,那麼它也會拋出一個錯誤。 我們自己可能知道它不會為空白,但類型檢查器不知道。 所以我們要告訴類型檢查器,它不會為空白,這時就要用到非空斷言操作符。
Angular 模板中的**非空斷言操作符(!)也是同樣的用途。
例如,在用*ngIf來檢查過hero是已定義的之後,就可以斷言hero屬性一定是已定義的。
src/app/app.component.html content_copy<!--No hero, no text --><div *ngIf="hero">  The hero's name is {{hero!.name}}</div>
在 Angular 編譯器把你的模板轉換成 TypeScript 代碼時,這個操作符會防止 TypeScript 報告 "hero.name可能為null或undefined"的錯誤。
與安全導航操作符不同的是,非空斷言操作符不會防止出現null或undefined。 它只是告訴 TypeScript 的類型檢查器對特定的屬性運算式,不做 "嚴格空值檢測"。
如果我們開啟了嚴格控制檢測,那就要用到這個模板操作符,而其它情況下則是可選的。
(4) 插值運算式的實現
<h3>  {{title}}  <img src="{{heroImageUrl}}" style="height:30px"></h3>
表面上看,我們在元素標籤之間插入了結果和對標籤的屬性進行了賦值。 這樣思考起來很方便,並且這個誤解很少給我們帶來麻煩。 但嚴格來講,這是不對的。插值運算式是一個特殊的文法,Angular 把它轉換成了屬性綁定。屬性綁定後面會說到。
3. 綁定文法 資料繫結是一種機制,用來協調使用者所見和應用資料。 雖然我們能往 HTML 推送值或者從 HTML 拉取值, 但如果把這些瑣事交給資料繫結架構處理, 應用會更容易編寫、閱讀和維護。 只要簡單地在繫結來源和目標 HTML 元素之間聲明綁定,架構就會完成這項工作。
(1) 綁定類型 a)單向從資料來源到視圖目標
插值運算式 {{expression}}
DOM Property綁定 [target]="expression"
HTML Attribute綁定 [attr.target]="expression"
CSS 類綁定 [class.class-name]="expression"
樣式綁定 [target]="expression"
b) 單向從視圖目標到資料來源
事件綁定 (target)="statement"
c) 雙向繫結
[(target)]="expression"
(2) HTML attribute 與 DOM property 的對比 介紹綁定之前,還是先看一個重要的問題:HTML attribute 與 DOM property 的對比.要想理解 Angular 綁定如何工作,重點是搞清 HTML attribute 和 DOM property 之間的區別。
attribute 是由 HTML 定義的。property 是由 DOM (Document Object Model) 定義的。
少量 HTML attribute 和 property 之間有著 1:1 的映射,如id。
有些 HTML attribute 沒有對應的 property,如colspan。
有些 DOM property 沒有對應的 attribute,如textContent。
大量 HTML attribute看起來映射到了property…… 但卻不像我們想的那樣。


attribute 初始化 DOM property,然後它們的任務就完成了。property 的值可以改變;attribute 的值不能改變。

舉個例子: 
<input type="text" value="name" (input)="onPut($event)">
import {Component, OnInit} from '@angular/core';@Component({  selector: 'app-angular',  templateUrl: './angular.component.html',  styleUrls: ['./angular.component.css']})export class AngularComponent implements OnInit {  constructor() {  }  ngOnInit(): void {  }  onPut(event) {    console.log('DOM 屬性: ' + event.target.value);    console.log('HTML 屬性: ' + event.target.getAttribute('value'));  }}
如下圖所示,我們可以看到隨著我們的輸入,DOM屬性會變化,但是html屬性不會發生變化。



在看一個關於disabled的例子:
<button disabled>點擊</button>
當前這個button是不可以點擊的,因為出現了disabled屬性。
<button disabled="false">點擊</button>
當我將disables(html屬性)設定為false,這個button還是不可以的。添加或刪除disabled attribute會禁用或啟用這個按鈕。但 attribute 的值無關緊要,這就是我們為什麼沒法通過 <button disabled="false">仍被禁用</button>這種寫法來啟用按鈕。
但是我們可以通過DOM屬性來啟用button。
<button [disabled]="false">點擊</button>
模板綁定是通過 property 和事件來工作的,而不是 attribute。在 Angular 的世界中,attribute 唯一的作用是用來初始化元素和指令的狀態。 當進行資料繫結時,只是在與元素和指令的 property 和事件打交道,而 attribute 就完全靠邊站了。
4 繫結目標 (1) 單向從資料來源到視圖目標 a) 插值運算式
{{employee.name}}
b) 屬性綁定(DOM屬性綁定) 
//[target]="expression"<input type="text" [value]="name" />
有些人喜歡用bind-首碼的可選形式,並稱之為規範形式:
<input type="text" bind-value="name" />
屬性綁定還是插值運算式。
<p><img src="{{heroImageUrl}}"> is the <i>interpolated</i> image.</p><p><img [src]="heroImageUrl"> is the <i>property bound</i> image.</p>
當要渲染的資料類型是字串時,沒有技術上的理由證明哪種形式更好。 我們傾向於可讀性,所以傾向於插值運算式。 建議建立代碼風格規則,選擇一種形式, 這樣,既遵循了規則,又能讓手頭的任務做起來更自然。但資料類型不是字串時,就必須使用屬性綁定了。
c) attribute綁定
[attr.target]="expression"
可以通過attribute 綁定來直接設定 attribute 的值。

為什麼 Angular 還提供了 attribute 綁定呢。
因為當元素沒有屬性可綁的時候,就必須使用 attribute 綁定。
<tr><td colspan="{{ 1 + 1 }}">One-Two</td></tr>


正如提示中所說,<td>元素沒有colspan屬性。 但是插值運算式和屬性綁定只能設定屬性,不能設定 attribute。我們需要 attribute 綁定來建立和綁定到這樣的 attribute。

attribute 綁定的文法與屬性綁定類似。 但方括弧中的部分不是元素的屬性名稱,而是由attr首碼,一個點 (.) 和 attribute 的名字組成。 可以通過值為字串的運算式來設定 attribute 的值。

這裡把[attr.colspan]綁定到一個計算值:
 <tr><td [attr.colspan]="1 + 1">One-Two</td></tr>
 d) CSS 類綁定 藉助 CSS 類綁定,可以從元素的class attribute 上添加和移除 CSS 類名。CSS 類綁定綁定的文法與屬性綁定類似。 但方括弧中的部分不是元素的屬性名稱,而是由class首碼,一個點 (.)和 CSS 類的名字組成, 其中後兩部分是可選的。形如:[class.class-name]。

舉個例子:
.color-class {  color: red;}
<div>  <div class="color-class">    <p>Test the css class bind</p>  </div></div>
此時頁面上的文字為紅顏色。

然後我們使用[class]來綁定,可以把它改寫為綁定到所需 CSS 類名的綁定;這是一個或者全有或者全無的替換型綁定。
<div>  <div class="color-class" [class]="className">    <p>Test the css class bind</p>  </div></div>
這樣的話就設定[class]上的類名到div上,class="color-class"會被替換掉。這種方式顯得太暴力了點,可能我只想操作某一個class。那麼可以使用下面的方式。可以綁定到特定的類名。 當模板運算式的求值結果是真值時,Angular 會添加這個類,反之則移除它。
<div [class.special]="isSpecial">The class binding is special</div>
還有一個ngClass內建指令,等到指令篇章學習。
e) 樣式綁定 通過樣式綁定,可以設定內聯樣式。
[style.style-property]
樣式綁定的文法與屬性綁定類似。 但方括弧中的部分不是元素的屬性名稱,而由style首碼,一個點 (.)和 CSS 樣式的屬性名稱組成。 
<button [style.color]="isSpecial ? 'red': 'green'">Red</button><button [style.background-color]="canSave ? 'cyan': 'grey'" >Save</button>
有些樣式綁定中的樣式帶有單位。在這裡,以根據條件用 “em” 和 “%” 來設定字型大小的單位。
<button [style.font-size.em]="isSpecial ? 3 : 1" >Big</button><button [style.font-size.%]="!isSpecial ? 150 : 50" >Small</button>
還有一個ngStyle內建指令,等到指令篇章學習。
(2) 單向從視圖目標到資料來源 a)事件綁定
(target)="statement"
圓括弧中的名稱 —— 比如(click) —— 標記出目標事件。在下面例子中,目標是按鈕的 click 事件。
<button (click)="onSave()">Save</button>
有些人更喜歡帶on-首碼的備選形式,稱之為規範形式:
<button on-click="onSave()">On Save</button>
b) $event 和事件處理語句 綁定會通過名叫$event的事件對象傳遞關於此事件的資訊(包括資料值)。

事件對象的形態取決於目標事件。如果目標事件是原生 DOM 元素事件, $event就是 DOM事件對象。
 <button (click)="onSave($event)">Save</button>
c) EventEmitter自訂事件 令使用 Angular EventEmitter 來觸發自訂事件。 指令建立一個EventEmitter執行個體,並且把它作為屬性暴露出來。 指令調用EventEmitter.emit(payload)來觸發事件,可以傳入任何東西作為訊息載荷。 父指令通過綁定到這個屬性來監聽事件,並通過$event對象來訪問。詳情可以查看Output.
(3) 雙向資料繫結 我們經常需要顯示資料屬性,並在使用者作出更改時更新該屬性。
在元素層面上,既要設定元素屬性,又要監聽元素事件變化。
Angular 為此提供一種特殊的雙向資料繫結文法:[(x)]。 [(x)]文法結合了屬性綁定的方括弧[x]和事件綁定的圓括弧(x)。
a) [( )] = 盒子裡的香蕉 舉例: 
//step.component.html<div>  <button (click)="dec()" title="smaller">-</button>  <button (click)="inc()" title="bigger">+</button>  <label [style.font-size.px]="size">FontSize: {{size}}px</label></div>
//step.component.tsimport {Component, EventEmitter, HostListener, Input, Output} from '@angular/core';@Component({  selector: 'app-step',  templateUrl: './step.component.html',  styleUrls: ['./step.component.css']})export class StepComponent {  @Input()  size: number;  @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);  }}
//angular.component.html<app-step [(size)]="fontSizePx"></app-step><div [style.font-size.px]="fontSizePx">Resizable Text</div>
//angular.compoent.tsimport {AfterViewInit, Component, ElementRef, OnInit, ViewChild} from '@angular/core';import {Employee} from './angular.module';@Component({  selector: 'app-angular',  templateUrl: './angular.component.html',  styleUrls: ['./angular.component.css'],})export class AngularComponent {  public fontSizePx: number = 12;  constructor() {  }}
StepComponent: size的初始值是一個輸入值,來自屬性綁定。(譯註:注意size前面的@Input) 點擊按鈕,在最小/最大值範圍限制內增加或者減少size。 然後用調整後的size觸發sizeChange事件。

雙向繫結文法實際上是屬性綁定和事件綁定的文法糖。 Angular將StepComponent的綁定分解成這樣:
<app-step [size]="fontSizePx" (sizeChange)="fontSizePx=$event"></app-step>
b) ngModel 使用 ngModel 時需要 FormsModule
在使用ngModel指令進行雙向資料繫結之前,我們必須匯入FormsModule並把它添加到Angular模組的imports列表中。
<input [(ngModel)]="currentHero.name">
回頭看看name綁定,注意,你可以通過分別綁定到<input>元素的value屬性和input事件來達到同樣的效果。
<input [value]="currentHero.name" (input)="currentHero.name=$event.target.value" >
那樣顯得很笨重,誰會記得該設定哪個元素屬性以及當使用者修改時觸發哪個事件。 你該如何提取輸入框中的文本並且更新資料屬性。誰會希望每次都去查資料來確定這些。

ngModel指令通過自己的輸入屬性ngModel和輸出屬性ngModelChange隱藏了那些細節。
<input [ngModel]="currentHero.name" (ngModelChange)="currentHero.name=$event">
ngModel輸入屬性會設定該元素的值,並通過ngModelChange的輸出屬性來監聽元素值的變化。

*各種元素都有很多特有的處理細節,因此NgModel指令只支援實現了ControlValueAccessor的元素, 它們能讓元素適配本協議。 <input>輸入框正是其中之一。 Angular為所有的基礎HTML表單都提供了值訪問器(Value accessor),表單一章展示了如何綁定它們。

參考: https://www.angular.cn/guide/template-syntax

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.