AngularJS 為什麼如此火呢?

發表於2013-07-05

【伯樂線上注】:上週我們在微博推薦了英文原文,感謝@靜聽梵音-破狼 的翻譯分享。如果其他朋友也有不錯的原創或譯文,可以嘗試推薦給伯樂線上

 

在本文中讓我們來逐步發掘angular為什麼如此火:

AngularJS是一個MV*(Model-View-Whatever,不管是MVC或者MVVM,統歸MDV(model Drive View))JavaScript框架,其是Google推出的SPA(single-page-application)應用框架,其為我們的web應用開發增加不少魔法變換。

我可以花整天的時間告訴你為什麼你必須在新專案嘗試angular.js,但是我覺得還是百說不如一練。

 

資料繫結和scopes(作用域)

首先第一個浮出大腦的問題是:angular支援資料繫結嗎?下面讓我們來了解angular.js的資料繫結:
Edit in plucker

 

在這程式碼片段中,在我們解釋細節之前,我還是希望嘗試下其效果:

注:此刻暫時不要太心急去了解ng-app。

如你所見,我在input中輸入的將會顯示在後邊echo。這是如何工作的?簡單來說,angular的ng-model(更多關於指令的將在文章後續)給我帶來了雙向繫結機制。

如此是好,但是user.name儲存在哪裡呢?其儲存在我們的$scope上,當我們在input中輸入任何字元都會及時的更新scope物件上的user.name屬性。然後我們可以利用angular的表示式{{…}}現實在HTML中。所以當我們在input中輸入時,其會及時更新scope上的user,name屬性,在由修改HTML顯示。

好吧,這並不難,但是你所說的$scope是個什麼東東呢?在angular中$scope是連線controllers(控制器)和templates(模板view/檢視)的主要膠合體。我們可以把我們的model存放在scope上,來達到雙向你繫結。

這就好比:

這意味著我們我們從template上為$scope設定了一個屬性物件user.name,所以我們也可以在controller中訪問這個物件(user.name).

讓我們來看個更復雜的示例:
Edit in plunker

 

在這裡首先我們定義了angular application,只是簡單的建立了一個angular module,其接受一個module名字和依賴陣列為引數。

緊接著建立了一個controller,通過呼叫 app module的controller方法,並傳入一個controller 名字和function。function函式接受$scope引數(可以接受更多的引數,放在後面部分)。所以我們可以開始雙向繫結了。

在$scope中我們附加了message的字串屬性。

在view中你可能注意到了body tag多出了一些東東,這是幹什麼的?這些是angular的指令(directives),它給HTML帶來了新的語法擴充套件,在這例子中我們使用了兩個angular內建的指令:

  • ng-app:它會告訴angularbody節點包含了我們的angular應用,換句話說,在body中的一切會被angular所接受管理。其引數為我們的app module的名字,和我們在javascript中命名一致。
  • ng-controller:在這指令在我們傳入的是controller 名字,此例中為MainCtrl。

最後我們將message插入我們的remplate。

所以其視覺化表示將是:

聰明的你可以冒出一個疑問:我們能夠在$scope上繫結function?當然。
Edit in plunker

 

我在示例controller中很容易瞭解到如何新增function到$scope。示例中function將修改$scope.message為“hello ,”和從input輸入的$scope.user.name的字串連線。

然後在HTML中建立一個附加了angular ng-click 指令的button。ng-click指令是的button在被點選時會執行我們為其賦值的greet()表示式。

注意:在input中enter並不會工作,這是展示ng-click如何工作。

指令

我們已經看見了一些指令了,指令是個什麼東東?指令為HTML引入了新的語法。HTML已經很強大了,但是有時我需要更多…

看下面的例子:

示例程式碼在做什麼?除了看見id外,我真的什麼也不能獲知。

然後我們只得從多餘30個javascript檔案中去查詢,最後我們看見如下程式碼:

Aha!原來是個餅圖(pie chart)容器。

在這裡如果你不去查詢javascript檔案將無法獲知頁面到底是做什麼的,實現了什麼功能。

下面我們再來看看angular code,

是不是語義很清晰,我們可以一眼看出這是一個pie chart,不僅如此,而且還知道width,height,以及其資料。

如果你對pie chart 示例感興趣,請猛擊這裡

angular內建指令

angular給我帶來了大量的內建指令。我們已經在前面看見了ng-app,ng-controller,ng-click,ng-model(angular的內建指令都以ng開始),接下來讓我瞭解更多的內建指令。

有時在頁面中有部分內容我們只希望到達某狀態(屬性為true)才顯示:
Edit in plunker

ng-show僅當angular其表示式值為true時,才顯示該元素或子元素。

注意:在這裡對於ng-click我們並不是直接在controller中建立function(此刻我們沒真正的controller),利用angular表示式作為指令的引數。在首次表示式為undefined,然後我們設定為為true,在false如此交替。

angular同時也提供了ng-hide指令。

讓我們看些更有趣的指令,如果有個List或者陣列呢?
Edit in plunker

 

棒極了,我們在controller中定義了一個list物件,在HTML用ng-repeat就能簡單的顯示了。

它是如何工作的?

ng-repeat會為集合中的每一項建立一個新的模板,在示例中有四項資料,將會重複建立下面code四次,

每次複製都會建立自己新的scope,我們沒有為每項手動建立scope,我們可以把scope理解為其scope,但是在這裡我們仍然能夠訪問父scope。

視覺化的展示為:

我們能自定義directive?

當然,我們能以不同粒度方式建立angular的directive,例如modal dialogs accordions, paginators, charts,search from …
angular指令總是與視覺化有關?不,我們仍然可以建立一些非視覺化的指令集。

讓我們來看一個例子吧:

回到我們上面的greet示例:

已經能夠很好的工作了,但是我們希望能夠在頁面初始化的時候游標焦點聚焦在輸入框input。jQuery?jQuery提供了focus函式,能夠很簡單的完成,但是這裡是angular教程,所以我們需要以angular way,顯得我們更專業些…

同時我們也希望我們的HTML能夠有自描述能力(譯者注:現代軟體開發特別語言語義更重要,如linq,guava,restfull…) ,所以angular directive肯定是個好的選擇。

接下來,我們可以在可以HTML中標註angular directive(angular directive首字母小寫駝峰命名,在前臺轉換為全小寫-分割風格)。

directive是angular中最複雜的要點,這裡只是最簡單的directive而已,如果可能這將放在以後文章,這裡並不會深入。

directive需要一個object的返回物件,我們可以定義一些需要關注的屬性,在示例中我們返回了一個link的連結函式(link函式主要作為directive的行為繫結), 我們如果需要,也可以替換HTML中模板。

Link function有3個引數(準確應該是是4個)scope,節點element,還有所有HTML attribute iAttrs。在link函式裡我們可以繫結click,mouseenter等事件,註冊指令行為。

在示例中我們為指令節點使用了focus操作。對element瞭解更多,你可以移步到這裡

我們可以很簡單的使用指令如下:
Edit in plunker

 

目前我們看見的directive都很簡單,如何利用指令渲染上面說的固定模板呢?

如下:

這裡返回的是帶有一些attribute的object。

  • restrict:指令的使用方式
  1. Attribute 形如:<div foo></div>.
  2. Element 形如:<foo></foo>
  3. Class 形如: <div class=”foo”></div>
  4. CoMment 形如: <!– directive: foo –>
  • replace:詢問是不是需要利用我們的模板替換原來的節點。
  • template:我們需要append或者replace到原節點的html模板。

directive還有很多的可配置options,如編譯compile,template url …

在示例我們不需要行為的繫結,所有沒有link function。其使用如下:
Edit in plunker

Filters(過濾器)

假想我們有個購物車的view顯示如下:

我們如何利用angular表示式顯示為貨幣格式?形如:$1,232.12。

相當簡單,angular為我們提供了叫filter得東東,過濾器其好比unix中的管道pipeline。angular同時也內建了貨幣currency filter。如你所見,我們可以用| 使用filter,這和unix管道模型很相似。我們也可以使用|連結更多的filter。

例如我們可以對開發人員簡單排序,在用ng-repeat顯示出來:

在這裡你發現了一些很有趣的事?衛門你可以給filter傳遞引數!

OrderBy filter會接受一個屬性名,並以它進行排序,示例中我們使用 name,如果你希望反序排列,你可以用 -name表示。
馬上你可能會冒出你頭腦:假想我們不止4個開發人員,有300,並且我們希望通過 name,country過濾呢?

非常簡單:
Edit in plunker

在示例中請注意我們是如何繫結search.name的,此處利用name 做filtering。filter的引數不會改變,繫結是search物件,會根據我們在input中輸入改變,而filter則會找尋search物件中的name屬性。

到這裡我希望你也像我一樣一樣興奮起來了!

下面我們來自定義filter呢?實現單詞首字母大寫 filter:

這裡我們自定義了一個filter其接受輸入引數input和過濾器引數param的一個函式。

接下來我們將在view使用它:

Services

在文章最後,我們需要再次較少下services。這是一個的維護應用程式功能邏輯部分,他是一個單間模式singleton。

為了保持應用程式的邏輯層次分明,更趨向於將其業務邏輯放到不同的services,保持controller的邏輯只有流程控制和view互動邏輯。

angular內建了很多services,如$http http請求,$q 非同步promises程式設計模式…在這裡我們不會討論angular的內建services,由於有很多的services,並且很難一次性解釋完,將在後續文章。我們將建立一個簡單的自定義services。

在controller之間共享資料對我們很有用,每個controller都有自己的scope所以我們不能將其繫結到其他的controller。所以解決方案是services,可以吧資料共享到services,在需要用到的地方引用它。

首先我們來看看如果不用services,我們將會遇見什麼問題:

我們使用了相同的ng-model,預期當一個input改變時候會及時更新到另一個input,如下:

但是實際情況卻是:

接下來需要藉助services來解決這個問題,利用services將user name在controller之間共享。

這裡用的是factory去建立一個service。angular中還有其他更高階的方式去建立service,如service,provider,這將會在後續文章詳解。

這裡有很多方式去建立service,我們選擇的是建立了一個帶有name預設值的user物件,並返回它。

在controllers中如何去使用呢?如下:
Edit in plunker

現在我們的程式形如:

酷極了。

現在我們的$scope.user在MainCtrl和SecondCtrl都用的是UserInformation,並且service是單例的,所以當我們更新其中一個controller的時候,另外一個也將會被更新。也有你又有了一個疑問:UserInformation引數是從哪裡來的?

angular核心是DI(依賴注入)在需要使用的地方會自定注入service。DI將不會在本節中講述,我們可以簡單的說,你建立了一個service,你可以在module作用域的controller,directive,甚至是其他service作為引數來輕鬆使用。

也許你對上面出現的$scope認為他也是個service,其實這是一個例外,其並不是真正的service注入到我們的controller。

 

總結

到這裡我們完成了第一篇但不是最後一篇angular部落格。Angular.js是一個優秀的框架,我敢肯定你也愛上了它。希望能在下片文章中仍然能見到你的倩影。希望你能喜歡這篇文章,也能夠評論些你的觀點。

相關文章