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裡面,只要把以下內容添加到<html>標籤中(或者從技術上說,可以添加到任何標籤中):
複製代碼 代碼如下:
<html ng-app="MyAwesomeApp">
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"關鍵字來調用傳遞給它的構造方法,然後再返回結果。所以,前面的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');});