The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

前端工程的極致精品: AngularJS 開發框架介紹

有好長一段時間,一直在尋尋覓覓一套好用的前端 JavaScript 框架,看過了 ExtJSBackboneJSEmberJSKnockoutJS、… 與各家比較後,最後終於情定 AngularJS 這套。其優異的框架設計像是 宣告式語法 (Directives)、DOM Templates、雙向資料繫結 (Two Way Data-Binding)、相依性注入 (Dependency Injection) 與關注點分離等特性,都深深地打動著我,但神奇的是,在台灣竟然看不到幾篇關於 AngularJS 的文章,這感覺就跟我三年前毅然決然踏入 ASP.NET MVC 的領域一樣,不過,不管別人用不用,我是用定了! (^_^)

AngularJS 框架介紹

一個由 Google 傾力打造的前端 JavaScript 框架,與其他 JS 框架最大的不同在於,他直接延伸現有的 HTML 架構,透過 宣告式語法 (Directives Syntax) 直接賦予 HTML 額外的超能力,讓 Web 應用程式在元件化的過程變得極其簡潔有力。我在 ASP.NET MVC 分享中常講的「關注點分離」與「以習慣取代配置」特性,在 AngularJS 框架中可謂落實的鉅細靡遺。

其「關注點分離」的部分,在於 控制器 (Controllers) 與 檢視 (Views) 之間切割的非常乾淨,再搭配 模組 (module) 與 相依性注入 (Dependency Injection) 相關實作,如 工廠 (factory) 與 服務 (service)、提供者 (provider) 與 常數值 (value) 等等,在在落實了「關注點分離」這個觀念。一般來說,越強調開發概念、架構越抽象的東西,越不容易上手,但對一個有經驗的開發人員來說,AngularJS 絕對是一個不可多得的好物,而對新手來說,也正好是個磨練的好機會。

而「以習慣取代配置」部分,AngularJS 確實有其獨到之處,他所設計的 宣告式語法 (Directives) 直接延伸 HTML 的能力,讓許多 AngularJS 自訂的 HTML 屬性自然而然地融入 HTML 之中,並且賦予其意義,而這就是所謂的 習慣 (Convention)。這是大多數 JS 框架不敢做的嘗試,也因為這樣,這樣的設計觀點並不是所有人都能接受,信者恆信、不信者恆不信,變成一種信仰(belief),我只是剛好成為信徒而已。

另外,在大多數 JS 框架當中,都會實作所謂的範本引擎 (Template Engine),但大多數範本引擎都是利用「字串」型態來定義網頁片段的範本,然後透過 JavaScript 進行變數字串取代後,再將字串插入到原本的 DOM 樹系之中,所以會有一些隱含的型別轉換成本。但是在 AngularJS 裡,當瀏覽器將 HTML 與這些 AngularJS 自訂的語法解析成 DOM 物件之後,AngularJS 會直接將原生的 DOM 物件當作網頁片段的範本,然後直接以 DOM 物件 (原生的 JavaScript 物件) 進行操作,大幅減少型別轉換的成本,相對的在範本操作的過程,其效能也比其他框架來的高出許多,這也就是 AngularJS 之中所謂的 DOM Templates 特性。

AngularJS 所提供的 雙向資料繫結 (Two Way Data-Binding) 特性,可以說是最酷最實用的功能之一,但這個特性並不是 AngularJS 所獨有,其他 JS 框架也大多都有此特性,不過對於沒有接觸過其他框架的人來說,確實是一個非常酷炫有趣的功能之一。

 

沒有銀子彈

與其他所有的 JS 框架一樣,這個世界沒有銀子彈,不會有任何一套框架可以解決所有問題,當然這套 AngularJS 也不例外。所以,要能理解 AngularJS 所擅長與不擅長的領域,可以有助於你評估與理解是否要採用 AngularJS 當作你未來的開發框架。

AngularJS 不像 jQuery 框架。在 jQuery 裡面,它提供許多底層的 API 可供你靈活運用。而在 AngularJS 裡面,卻提供的是一套完整的框架,試圖解決某個難題,而 AngularJS 所企圖解決的難題,正是 CRUD 類型的應用程式。就像每個有寫過幾年 Web 開發經驗的人 (無論甚麼程式語言),心中都會有一套自己的 CMS (內容管理系統) 開發架構,也就是處裡那些繁瑣的 C (建立資料)、R (讀取資料)、U (更新資料)、D (刪除資料) 等操作,你也許可以自己回想一下,在我們歷年來的各種大大小小的網站,那個網站不是都在處理這些類型的資料。以網站前台來說,是不是大多都是從資料庫讀取資料,然後呈現在頁面上?再以網站後台來說,大多也都是資料的 新刪查改 (新增、刪除、查詢、修改)。但在這之前,沒有人會限制你怎麼做,但是 AngularJS 卻是規定你要怎麼做,用 AngularJS 所設計的方式來做,而且 AngularJS 的設計團隊相信,這就是實作 CRUD 最好的方式。 ( 當然,其他框架也是這麼想的 XD )

所以,除了 CRUD 類型以外的 Web 應用程式,AngularJS 幾乎可以說是英雄無用武之地,例如你要設計複雜的 Web 遊戲或是開發那些必須要精細控制 DOM 物件的應用程式,都不應該用 AngularJS 來做,否則肯定會讓你寫到吐血身亡。

:常用 jQuery 的人,應該會經常習慣性的操作 DOM 物件,轉到 AngularJS 之後,必須要改變習慣,改用 MVC資料繫結 的方式進行操作,這點會帶來一些些轉換成本學習曲線 (learning curve)。

:在 Angular 裡面有內建一個 jqLite 套件,包含了一些基本的 DOM 操作,但也只有一點點而已。不過,這並不代表不能使用 jQuery 進行操作 (還是可以使用 jQuery 的意思),只是比較難跟 Angular 搭配運作而已。如果你的 HTML 頁面中有載入 jQuery 的話,兩者並不會發生衝突,而且會以你額外載入的 jQuery 為主。

:前面講的這麼多,我自己都認為 Web 開發的新手(newbie)可能會看不懂,但如果你日後開始撰寫一些 AngularJS 程式碼的話,可以再回來看看上述介紹,或許會有不同的體會。

 

AngularJS 快速上手

AngularJS 提供一套高度抽象化的架構來簡化 CRUD 類型的 Web 應用程式開發,你必須要先了解它的開發習慣,才能理解到底應該怎樣開發 AngularJS 程式,以下我就先用一個基本的例子,帶領大家快速上手,我會以 JS Bin 網站當作示範,各位不用註冊會員就可以利用 JS Bin 快速體驗 AngularJS 的魅力。

1. 連到 http://jsbin.com/ 網頁,先點擊 Add Library 並加入 Angular 的穩定版本,如下圖示:

 

2. 在 <html> 標籤上,加上一個 ng-app 屬性

這就是所謂的 宣告式語法 (Directives),以 ng-app  來說,這是用來宣告整份 html 都屬於 AngularJS 的管轄!

 

3. 示範 Angular 表達式 (Angular Expressions)

Angular 表達式是一個長得很像 JavaScript 的語法,但又不全然是 JavaScript,至少你不能把它當成 JavaScript 來看待,只是語法相近而已,且 Angular 表達式會用 {{}} 包起來,例如:{{ 1 }}

接著請你在 JS Bin 的 <body> 標籤裡,加上以下 Angular 表達式,先去體會一下:

{{ 9999 }}
<br>
{{ 9999+1 }}
<br>
{{ 9*9 }}
<br>
{{ 'Hello World' }}

JS Bin 右側的 Output 視窗你會立即看到經由 AngularJS 運算後的結果,如下圖示。這時你應該可以體會到,目前的語法,都是跟 JavaScript 一樣的,就是輸出數值與字串而已。

 

4. 示範 AngularJS 的 Filter 特性 (Understanding Angular Filters)

Angular Filters 可以修飾過濾 Angular 表達式輸出的內容,這裡我簡單列出幾個例子,請你在 JS Bin 的 <body> 標籤裡,把所有內容換成以下含有 Filter 的 Angular 表達式,先去體會一下:

{{ 9999 | number }}
<br>
{{ 9999+1 | number:2 }}
<br>
{{ 9*9 | currency }}
<br>
{{ 'Hello World' | uppercase }}

修改完後的輸出如下圖示: ( 你覺得我還需要用文字說明嗎?程式設計師應該看了有感覺對吧?尤其是用過 Smarty Template Engine 的開發人員,希望我還有 PHP 的讀者,哈哈 )

 

5. 示範資料繫結 (Data Binding)

在 AngularJS 裡,所有在 View 與 Controller 之間,都是透過 Model 來做資料傳遞,無論你在 View 這端透過表單元素修改了內容,或是在 Controller 這端修改了 Model 內容,兩邊都會即時發生變化,因為在 AngularJS 框架中會監控 (watch) Model 物件的任何變化,並隨時反映到 View 上面。以下是雙向資料繫結的示意圖:

接下來,我用一個極簡單的例子,示範 Angular 資料繫結的寫法。請你在 JS Bin 的 <body> 標籤裡,把所有內容換成以下 HTML,先去體會一下 Angular 資料繫結的神奇魅力:

數量: <input type="number" ng-model="quantity" ng-init="quantity = 1">
<br>
單價: <input type="number" ng-model="price" ng-init="price = 299">
<br>
總價: {{ quantity * price }}

在上述語法中,有兩個 input 欄位,都被 ng-model 屬性宣告成了 Model,屬性值中設定的事 Model 的變數名稱。不過,如果你試圖在 input 標籤設定 value 屬性與值,其屬性值並不會顯示在欄位裡,這是因為目前這個 input 欄位已經受到 Angular 所控制,所以欄位中的 value 一定會跟所設定的 Model 繫結,當 quantityprice 這兩個 Model 都沒有預設值時,因為雙向繫結的關係,會導致欄位並不會出現任何資料,這才需要透過 ng-init 來指定 Model 的預設值。

最後則是將兩個 Model 直接在 Angular 表達式中進行運算,你可以從以下動畫看出這個神奇的效果:
( 我知道你的嘴角已經微微上揚 XD )

[ 程式碼範例 ]

 

結語

本篇文章並不長,而且還有好多 AngularJS 的精美特性還沒提到,我會在本文末加上許多參考連結,有興趣的人可以持續進修,也或許在不久的將來,你能聽到我在某些場合分享 AngularJS 開發實戰。 (^_^)

 

相關連結