Angular 2模板語法

來源 http://kittencup.com/javascript/2015/07/20/Angular%202%E6%A8%A1%E6%9D%BF%E8%AF%AD%E6%B3%95.html


原文地址:http://victorsavkin.com/post/119943127151/angular-2-template-syntax

屬性和事件綁定

屬性和事件綁定在指令中是公開的API,數據從屬性綁定流入指令,從事件中流出指令

屬性綁定

假設我們有一個組件來呈現的Todo,我們可以在我們的模板中使用這個組件,如下所示:

<todo-cmp [model]="myTodo"></todo-cmp>

這告訴Angular,只要myTodo發生變化,當有一個新的todo時,Angular會通過模型來自動更新todo組件

事件綁定

現在,讓我們添加一個事件使組件更有趣。

<todo-cmp [model]="todo" (complete)="onCompletingTodo(todo)"></todo-cmp>

當事件complete觸發時會告訴Angular調用onCompletingTodo方法

現在,讓我們看看TodoCmp本身。

@Component({
  selector: 'todo-cmp',
  properties: ['model'],
  events: ['complete']})class TodoCmp {
  model;
  complete = new EventEmitter(); // TypeScript 支持初始化

  onCompletedButton() {
    this.complete.next(); // 觸發事件
  }}

這個組件聲明數據綁定的名字爲model,事件名爲complete

Angular使用Rx事件風格來處理事件的接收,EventEmitter即實現了observable,又實現了observer接口(規範),因此,我們可以用它來觸發事件,並且Angular也可以用它來監聽事件。

正如你所看到的,屬性和事件綁定的核心語法很簡單。在覈心語法之上,Angular提供了一些語法糖,使表達常用的編程模式更加容易。重要的是要了解,這僅僅是語法糖,而且它不會改變語義。

雙向綁定

雙向數據綁定在某些情況下是很方便的,最值得注意的是處理輸入,正如我剛纔提到的,屬性綁定用於數據從父傳遞給子,事件綁定用於從子到父的數據傳遞。因此,我們可以使用兩種方法來實現雙向綁定。

<input [ng-model]="todo.text" (ng-model)="todo.text=$event"></input>

雖然這可以正常工作,但這太羅嗦。因爲這是一個常見的模式,所以Angular提供語法糖簡化這種寫法。

<input [(ng-model)]="todo.text"></input>

要完成這個例子,讓我們來實現Angular 2的ng-model

@Directive({
  selector: '[ng-model]',
  properties: ['ngModel'],
  events: ['ngModelChanged: ngModel'],
  host: {
    "[value]": 'ngModel',
    "(input)": "ngModelChanged.next($event.target.value)"
  }
})
class NgModelDirective {
  ngModel:any; // stored value
  ngModelChanged:EventEmitter; // an event emitter
}

這是一種比較幼稚的ngModel實現,但它說明了如何實現雙向數據綁定行爲:輸入將在text發生更改時更新,並在輸入更改時更新text字段。

請注意,於Angular 1相反,你只要看看模板就可以知道哪些綁定是“雙向”,哪些是“單向”。

此外,因爲只有一個方向,屬性綁定,被Angular自動執行,雙向的行爲更可預測的。

它不會破壞任何Angular 2的語法:這只是一些語法糖,沒有別的。

我想提一提,你不用去實現NgModel。Angular 2配備了一個表單處理模塊,其包括NgModel的實現。

插值

<div>Hello `name`</div>

使用語法糖

<div [textContent]="interpolate(['Hello'], [name])"></div>

綁定直接量

<show-title title="Some Title"></show-title>

使用語法糖

<show-title [title]=" 'Some Title' "></show-title>

移除括號

你可以使用bind-,in-和bindon-在你的模板中代替所有的括號,雖然這幾乎不能稱爲“語法糖”

<some-component [prop]="someExp" (event)="someEvent()" [(two-way-prop)]="someExp"></show-title>

於上面相同

<some-component bind-prop="someExp" on-event="someEvent()" bindon-two-way-prop="someExp"></show-title>

局部變量

有兩個組件互相交互,這種情況並不少見,Angular 2在模板中支持定義的局部變量。

<video-player #player></video-player><button (click)="player.pause()">Pause</button>

#player表示當前video-player組件自身,而沒有#player的組件則可以通過player訪問video-player組件

<input #i>`i`.`value`

語法糖

<video-player #player></video-player>

相當於

<video-player var-player></video-player>

模板和 *

Angular以特殊的方式對待template元素。它們用來創建視圖,你可以動態操作DOM塊,*語法是一種捷徑,它可以使你不用寫出全部的<template>元素,讓我告訴你它是如何工作。

假設我們呈現Todo列表組件。

<todo-cmp *ng-for="#t of todos; #i=index" [model]="t" [index]="t"></todo-cmp>

去除語法糖後變爲

<todo-cmp template="ng-for #item of items; #i=index" [model]="t" [index]="i"></todo-cmp>

再一次去除語法糖後變爲

<template ng-for #item="$implicit" [ng-for-of]="items" #i="index">
  <todo-cmp [model]="t" [index]="t"></todo-cmp></template>

該ngFor指令在視圖上會創建$implicit和$index變量並綁定到模板上,在模板元素上聲明的所有變量只能在元素內提供,這就是爲什麼以下是不正確

<todo-cmp *ng-for="#t of todos"></todo-cmp>`t` <!-- t cannot be referenced here -->

你需要重點理解的是,當你建立你自己的指令來處理視圖時,你的 * syntax 語法能擴展成什麼。例如,如果你看ngfor,你會發現它有ngforof屬性,但是沒有of屬性。

爲什麼不對ng-for自定義語法,象angular 1一樣呢?這有幾個很好的理由。有自定義語法意味着你必須知道這個微語言如何操作。這也意味着在工具(例如,IDE和LInter)中不能理解你的模板而且並不能提供自動完成和重構。

web組件和原生元素

在這篇博客我談到了一切的內容 - 局部變量,屬性和事件綁定 - 對於web組件和標準的html元素來講使用方式是完全相同

我可以用Web組件更換TodoCmp,仍然使用相同方式與它進行交互。

<todo-cmp [model]="todo" (completed)="onCompletingTodo(todo)"></todo-cmp>

我可以用Web組件更換視頻播放器,仍然使用相同方式與它進行交互。

<video-player #player></video-player><button (click)="player.pause()">Pause</button>

這將變得極爲重要,因爲更多的組件庫可用。當運行在非Angular組件上也很重要(這是Angular 2目標之一),否者你不得不把每一個原生組件包裝成一個Angular 2組件,那真的很糟糕。Angular 2你可以直接使用任何本地組件,使用相同的語法,只有當你例如想使用依賴注入時,可將它包裝爲Angular組件

設計目標

我希望你能明白在Angular 2裏模板語法是怎麼運作的.現在,我想來討論一下爲什麼它用這種方式運作?它這麼設計的目的是什麼?

我們的主要設計目標是使模板更加清晰,開發者在不知如果使用指令情況也能夠理解和重構模板,以及指令是如何工作的。

<component [property1]="name" property2="name"></component>

不管組件元素是什麼,property1是指向一個name變量的屬性 property2屬性只表示一個name字符串,你也需要知道,組件的property2屬性無法更新,property1屬性綁定更新是從父到子。

<component [(property1)]="name"></component>

在這裏,我們可以看到,name可以被更新,因爲我們使用[()]語法

同樣,你可以告訴在模板中定義了哪些變量,來看這裏的*nf-for

<todo-cmp *ng-for="#t of todos"></todo-cmp>

其次,我們希望有豐富的開發工具,在下面的列子中,工具可以靜態地推斷出第一個index是組件上的字段,而第2個index是ng-for輸出的局部變量

`index`<div *ng-for="#item of items; var index=index">
  {{index}</div>

這就是其中的一個Angular 2模板的實例分析。由於IDE可以分析模板,所以他們可以提供自動完成和重構。

最後,我們要本地組件和web組件無縫集成。這意味着Angular 不能有特殊的特定事件(例如,ng-click),而必須提供通用機制,更新任何屬性或監聽任何事件。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章