AngularJS是什麼?
AngularJs(後面就簡稱ng了)是用來設計動態web應用的結構架構。首先,它是一個框架,不是類別庫,是像EXT一樣提供一整套方案來設計web應用。它不只是一個javascript框架,因為它的核心其實是對HTML標籤的增強。
何為HTML標籤增強?其實就是讓你能夠用標籤完成一部分頁面邏輯,具體方式就是透過自訂標籤、自訂屬性等,這些HTML原生沒有的標籤/屬性在ng中有一個名字:指令(directive)。後面會詳細介紹。那麼,什麼又是動態web應用程式呢?與傳統web系統相區別,web應用能為使用者提供豐富的操作,能夠隨使用者操作不斷更新視圖而不進行url跳轉。 ng官方也聲明它更適用於開發CRUD應用,也就是資料操作比較多的應用,而非遊戲或影像處理類應用。
為了實現這些,ng引入了一些非常棒的特性,包括模板機制、資料綁定、模組、指令、依賴注入、路由。透過資料與模板的綁定,能夠讓我們擺脫繁瑣的DOM操作,而將注意力集中在業務邏輯上。
另外一個疑問,ng是MVC框架嗎?還是MVVM框架?官網有提到ng的設計採用了MVC的基本思想,而又不完全是MVC,因為在書寫代碼時我們確實是在用ng-controller這個指令(起碼從名字上看,是MVC吧),但這個controller處理的業務基本上都是與view進行交互,這麼看來又很接近MVVM。讓我們把目光移到官網那個非醒目的title上:「AngularJS — Superheroic JavaScript MVW Framework」。
AngularJS中的Module類別負責定義應用程式如何啟動,它也可以透過宣告的方式定義應用程式中的各個片段。讓我們來看看它是如何實現這些功能的。
一.Main方法在哪裡
如果你是從Java或Python程式語言轉過來的,那你可能很想知道AngularJS裡面的main方法在哪裡?這個把所有東西啟動起來,第一個被執行的方法在哪裡? JavaScript程式碼裡面負責實例化並且把所有東西組合在一起,然後命令應用開始運行的那個方法在哪裡?
事實上,AngularJS並沒有main方法,AngularJS使用模組的概念來取代main方法。模組允許我們透過聲明的方式來描述應用程式中的依賴關係,以及如何進行組裝和啟動。使用這種方式的原因如下:
1.模組是宣告式的。這就意味著它寫起來更加容易,同時理解起來也很容易,閱讀它就像讀普通的英文一樣!
2.它是被模組化的。這就迫使你去思考如何定義你的元件和依賴關係,讓它們變得更加清晰。
3.它讓測驗變得更容易。在單元測試呂,你可以選擇性地加入模組,並且可以避免程式碼中存在無法進行單元測試的內容。同時,在場景測試中,你可以載入其他額外的模組,這樣就可以更好地和其他組件一起使用。
例如,在我們的應用上有一個叫做"MyAwesomeApp"的模組。在HTML裡面,只要把以下內容加到標籤中(或從技術上說,可以加到任何標籤中):
ng-app指令就會告訴AngularJS使用MyAwesomeApp模組來啟動你的應用程式。那麼,應該如何定義模組呢?舉例來說,我們建議你為服務、指令和篩選器分別定義不同的模組。然後你的主模組可以宣告依賴這些模組。
如此可以讓模組管理更容易,因為它們都是良好的、完整的程式碼區塊,每個模組有且只有一種職能。同時,單元測試可以只載入它們所關注的模組,這樣就可以減少初始化的次數,單元測試也會變得更精緻、更專注。
二.載入與依賴
模組載入動作發生在兩個不同的階段,這點從函數名稱上面就可以反映出來,它們分別是Config程式碼區塊和Run程式碼區塊(或稱為階段)。
1.Config程式碼區塊
在此階段裡面,AngularJS會連結並註冊所有資料來源。因此,只有資料來源和常數可以注入到Config程式碼區塊中。那些不確定是否已經初始化好的服務不能注入進來。
2.Run程式碼區塊
Run程式碼區塊用來啟動你的應用,並且在註射器創建完成之後開始執行。為了避免在這一點開始之後再對系統進行配置操作,只有實例和常數可以被注入到Run程式碼區塊中。你會發現,在AngularJS中,Run程式碼區塊是與main方法最類似的東西。
三.快速方法
利用模組可以做什麼?我們可以用它來實例化控制器、指令、過濾器以及服務,但利用模組類別還可以做更多事情。如下模組配置的API方法:
1.config(configFn)
利用此方法可以做一些註冊工作,這些工作需要在模組載入時完成。
2.constant(name, object)
此方法會先運行,所以你可以用它來宣告整個應用範圍內的常數,並且讓它們在所有配置(config方法)和實例(後面的所有方法,例如controller、service等)方法中可用。
3.controller(name,constructor)
它的基本功能是使用控制器方便後面使用。
4.directive(name,directiveFactory)
可使用此方法在應用程式中建立指令。
5.filter(name,filterFactory)
允許你創建命名的AngularJS過濾器,就像前面章節所討論的那樣。
6.run(initializationFn)
如果你想要在註射器啟動之後執行某些操作,而這些操作需要在頁面對使用者可用之前執行,就可以使用此方法。
7.value(name,object)
允許在整個應用中註射數值。
8.factory(name,factoryFn)
如果你有一個類別或對象,並且需要先為它提供一些邏輯或參數,然後才能對它初始化,那麼你就可以使用這裡的factory介面。 factory是一個函數,它負責建立一些特定的值(或物件)。我們來看一個greeter(打招呼)函數的實例,這個函數需要一個問候語來初始化:
function Greeter(salutation) { this.greet = function(name) { return salutation + ' ' + name; }; }
greeter函數範例如下:
myApp.factory('greeter', function(salut) { return new Greeter(salut); });
然後可以這樣來呼叫它:
var myGreeter = greeter('Halo');
9.service(name,object)
factory和service之間的不同點在於,factory會直接呼叫傳遞給它的函數,然後回傳執行的結果;而service將會使用"new"關鍵字來呼叫傳遞給它的建構方法,然後再傳回執行的結果;而service將會使用"new"關鍵字來呼叫傳遞給它的建構方法,然後再傳回執行的結果;而service將會使用"new"關鍵字來呼叫傳遞給它的建構方法,然後再傳回返回結果。所以,前面的greeter Factory可以替換成下面這個greeter Service:
myApp.service('greeter', Greeter);
每当我们需要一个greeter实例的时候,AngularJS就会调用新的Greeter()来返回一个实例。
10.provider(name,providerFn)
provider是这几个方法中最复杂的部分(显然,也是可配置性最好的部分)。provider中既绑定了factory也绑定了service,并且在注入系统准备完毕之前,还可以享受到配置provider函数的好处(也就是config块)。
我们来看看使用provider改造之后的greeter Service是什么样子:
myApp.provider('greeter', function() { var salutation = 'Hello'; this.setSalutation = function(s) { salutation = s; } function Greeter(a) { this.greet = function() { return salutation + ' ' + a; } } this.$get = function(a) { return new Greeter(a); }; });
这样我们就可以在运行时动态设置问候语了(例如,可以根据用户使用的不同语言进行设置)。
var myApp = angular.module(myApp, []).config(function(greeterProvider) { greeterProvider.setSalutation('Namaste'); });